diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index eb9f33319f02a..8b81b2a47da21 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -44,6 +44,9 @@ The .NET Foundation licenses this file to you under the MIT license. $ORIGIN @executable_path + + libeventpipe-disabled + libeventpipe-enabled @@ -51,6 +54,7 @@ The .NET Foundation licenses this file to you under the MIT license. + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets index fe5cdf1cd8638..5c115640adc8d 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.targets @@ -25,6 +25,8 @@ The .NET Foundation licenses this file to you under the MIT license. wmainCRTStartup WINDOWS CONSOLE + eventpipe-disabled + eventpipe-enabled @@ -33,6 +35,7 @@ The .NET Foundation licenses this file to you under the MIT license. + diff --git a/src/coreclr/nativeaot/Directory.Build.props b/src/coreclr/nativeaot/Directory.Build.props index 275f0398185b3..337bffde726f7 100644 --- a/src/coreclr/nativeaot/Directory.Build.props +++ b/src/coreclr/nativeaot/Directory.Build.props @@ -65,6 +65,14 @@ FEATURE_OBJCMARSHAL;$(DefineConstants) + + false + true + + + FEATURE_PERFTRACING;$(DefineConstants) + + diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index 69441fd7f5881..8c80cbe2f37a0 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -207,6 +207,14 @@ list(APPEND RUNTIME_SOURCES_ARCH_ASM convert_to_absolute_path(ARCH_SOURCES_DIR ${ARCH_SOURCES_DIR}) include_directories(${ARCH_SOURCES_DIR}) +if(NOT CLR_CMAKE_TARGET_ARCH_WASM) + set(FEATURE_PERFTRACING 1) +endif() + +if(FEATURE_PERFTRACING) + add_definitions(-DFEATURE_PERFTRACING) +endif() + add_definitions(-DFEATURE_BASICFREEZE) add_definitions(-DFEATURE_CONSERVATIVE_GC) add_definitions(-DFEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP) @@ -263,6 +271,10 @@ else() add_subdirectory(Portable) endif() +if(FEATURE_PERFTRACING) + add_subdirectory(eventpipe) +endif() + if (CLR_CMAKE_TARGET_UNIX) add_library(numasupportdynamic STATIC ${GC_DIR}/unix/numasupport.dynamic.cpp) install_static_library(numasupportdynamic aotsdk nativeaot) diff --git a/src/coreclr/nativeaot/Runtime/DisabledEventPipeInterface.cpp b/src/coreclr/nativeaot/Runtime/DisabledEventPipeInterface.cpp new file mode 100644 index 0000000000000..cb654d81e4c3b --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/DisabledEventPipeInterface.cpp @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +void EventPipeAdapter_Initialize() {} + +bool DiagnosticServerAdapter_Initialize() { return false; } +void DiagnosticServerAdapter_PauseForDiagnosticsMonitor() {} + +void EventPipeAdapter_FinishInitialize() {} + +void EventPipeAdapter_Shutdown() {} +bool DiagnosticServerAdapter_Shutdown() { return false; } diff --git a/src/coreclr/nativeaot/Runtime/EmptyContainers.h b/src/coreclr/nativeaot/Runtime/EmptyContainers.h new file mode 100644 index 0000000000000..f96af50e98bd3 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/EmptyContainers.h @@ -0,0 +1,321 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __EmptyContainers_h__ +#define __EmptyContainers_h__ + +// This header file will contains minimal containers that are needed for EventPipe library implementation +// shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase +// @TODO - this will likely be replaced by the common container classes to be added to the EventPipe library +// Hence initially, the bare boned implementation focus is on unblocking HW/Simple Trace bring up + +#include "EmptyContainers2.h" +#include "rhassert.h" + +struct SLink_EP +{ + SLink_EP* m_pNext; + + SLink_EP() + { + m_pNext = NULL; + } + + // find pLink within the list starting at pHead + // if found remove the link from the list and return the link + // otherwise return NULL + static SLink_EP* FindAndRemove(SLink_EP *pHead, SLink_EP* pLink, SLink_EP ** ppPrior) + { + + _ASSERTE(pHead != NULL); + _ASSERTE(pLink != NULL); + + SLink_EP* pFreeLink = NULL; + *ppPrior = NULL; + + while (pHead->m_pNext != NULL) + { + if (pHead->m_pNext == pLink) + { + pFreeLink = pLink; + pHead->m_pNext = pLink->m_pNext; + *ppPrior = pHead; + break; + } + pHead = pHead->m_pNext; + } + + return pFreeLink; + } +}; + + +// template +// Assumes fHead to be false +template +class SList_EP +{ +protected: + // used as sentinel + SLink_EP m_link; + SLink_EP* m_pHead; + SLink_EP* m_pTail; + + // get the list node within the object + static SLink_EP* GetLink (T* pLink) + { + return &(pLink->m_Link); + } + + static T* GetObject (SLink_EP* pLink) + { + if (pLink == NULL) + return NULL; + return reinterpret_cast(reinterpret_cast(pLink) - offsetof(T, m_Link)); + } + +public: + + SList_EP() + { + m_pHead = &m_link; + // NOTE :: fHead variable is template argument + // the following code is a compiled in, only if the fHead flag + // is set to false, + m_pTail = &m_link; + // TODO: Likely not needed now since SLink_EP has a ctor + m_link.m_pNext = NULL; + } + + bool IsEmpty() + { + return m_pHead->m_pNext == NULL; + } + + void InsertTail(T *pObj) + { + _ASSERTE(pObj != NULL); + SLink_EP *pLink = GetLink(pObj); + + m_pTail->m_pNext = pLink; + m_pTail = pLink; + } + + T* RemoveHead() + { + SLink_EP* pLink = m_pHead->m_pNext; + if (pLink != NULL) + { + m_pHead->m_pNext = pLink->m_pNext; + } + + if(m_pTail == pLink) + { + m_pTail = m_pHead; + } + + return GetObject(pLink); + } + + T* GetHead() + { + return GetObject(m_pHead->m_pNext); + } + + static T *GetNext(T *pObj) + { + _ASSERTE(pObj != NULL); + return GetObject(GetLink(pObj)->m_pNext); + } + + + T* FindAndRemove(T *pObj) + { + _ASSERTE(pObj != NULL); + + SLink_EP *prior; + SLink_EP *ret = SLink_EP::FindAndRemove(m_pHead, GetLink(pObj), &prior); + + if (ret == m_pTail) + m_pTail = prior; + + return GetObject(ret); + } + + void InsertHead(T *pObj) + { + //PalDebugBreak(); + } + + + class Iterator + { + friend class SList_EP; + //T* _t; + + public: + Iterator & operator++() + { + _ASSERTE(m_cur != NULL); + m_cur = SList_EP::GetNext(m_cur); + return *this; + } + + Iterator operator++(int) + { + Iterator it(m_cur); + ++(*this); + return it; + } + + bool operator==(Iterator const & other) const + { + return m_cur == other.m_cur || + (m_cur != NULL && other.m_cur != NULL && *m_cur == *other.m_cur); + } + + T & operator*() + { + _ASSERTE(m_cur != NULL); + return *m_cur; + } + + T * operator->() const + { + //PalDebugBreak(); + return m_cur; + } + + private: + // Iterator(SList * pList) + // : m_cur(pList->GetHead()) + // { } + + Iterator(T* pObj) + : m_cur(pObj) + { } + + Iterator() + : m_cur(NULL) + { } + + T* m_cur; + + }; + + Iterator begin() + { + return Iterator(GetHead()); + } + + Iterator end() + { + return Iterator(); + } + +}; + +template +struct SListElem_EP +{ + SLink_EP m_Link; + ElemT m_Value; + + operator ElemT const &() const + { + return m_Value; + } + + operator ElemT &() + { + return m_Value; + } + + ElemT const & operator*() const + { + //PalDebugBreak(); + return m_Value; + } + + ElemT & operator*() + { + //PalDebugBreak(); + return m_Value; + } + + SListElem_EP() + : m_Link() + , m_Value() + { + } + + SListElem_EP(ElemT val) + : m_Link() + , m_Value(val) + { + } + + ElemT & GetValue() + { + return m_Value; + } + +}; + +// Bare boned implementation to unblock HW +template +class CQuickArrayList_EP +{ +private: + size_t m_curSize; + T *m_array; + size_t maxSize; +public: + CQuickArrayList_EP() + : m_curSize(0), maxSize(100) + { + m_array = new T[maxSize]; + } + + + T* AllocNoThrow(size_t iItems) + { + return new T[iItems]; + } + + bool PushNoThrow(const T & value) + { + // if(m_curSize >= maxSize) + // PalDebugBreak(); + m_array[m_curSize++] = value; + return true; + } + + size_t Size() const + { + return m_curSize; + } + + T Pop() + { + T t = m_array[m_curSize]; + m_curSize--; + return t; + } + + void Shrink() + { + } + + T& operator[] (size_t ix) + { + return m_array[ix]; + } + + T* Ptr() + { + return m_array; + } +}; + +#endif // __EmptyContainers_h__ diff --git a/src/coreclr/nativeaot/Runtime/EmptyContainers2.h b/src/coreclr/nativeaot/Runtime/EmptyContainers2.h new file mode 100644 index 0000000000000..44036c21cd0ef --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/EmptyContainers2.h @@ -0,0 +1,548 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __EmptyContainers2_h__ +#define __EmptyContainers2_h__ + +// This header file will contains minimal containers that are needed for EventPipe library implementation +// shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase +// @TODO - this will likely be replaced by the common container classes to be added to the EventPipe library +// Hence initially, the bare boned implementation focus is on unblocking HW/Simple Trace bring up + +// TODO: Should shash.h FailureType be used instead? +enum FailureType_EP { ftAllocation_EP, ftOverflow_EP }; + +template < typename ELEMENT, typename COUNT_T = uint32_t > +class DefaultSHashTraits_EP +{ +public: + typedef COUNT_T count_t; + typedef ELEMENT element_t; + typedef element_t* PTR_element_t; + + static const count_t s_growth_factor_numerator = 3; + static const count_t s_growth_factor_denominator = 2; + + static const count_t s_density_factor_numerator = 3; + static const count_t s_density_factor_denominator = 4; + + static const count_t s_minimum_allocation = 7; + + static const bool s_NoThrow = true; + + static const ELEMENT Null() { return (const ELEMENT) 0; } + static const ELEMENT Deleted() { return (const ELEMENT) -1; } + static bool IsNull(const ELEMENT &e) { return e == (const ELEMENT) 0; } + static bool IsDeleted(const ELEMENT &e) + { + //PalDebugBreak(); + return false; + //return e == (const ELEMENT) -1; + } + + static void OnFailure(FailureType_EP /*ft*/) { } + +}; + +template +class SHash_EP : public TRAITS +{ + public: + class Index; + friend class Index; + class Iterator; + + typedef typename TRAITS::element_t element_t; + typedef typename TRAITS::PTR_element_t PTR_element_t; + typedef typename TRAITS::key_t key_t; + typedef typename TRAITS::count_t count_t; + + SHash_EP():m_table(nullptr), + m_tableSize(0), + m_tableCount(0), + m_tableOccupied(0), + m_tableMax(0) + { + } + + ~SHash_EP() + { + delete [] m_table; + } + + const element_t * Lookup(element_t* table, count_t tableSize, key_t key) const + { + if (tableSize == 0) + return NULL; + + count_t hash = TRAITS::Hash(key); + count_t index = hash % tableSize; + count_t increment = 0; // delay computation + + while (true) + { + element_t& current = table[index]; + + if (TRAITS::IsNull(current)) + return NULL; + + if (!TRAITS::IsDeleted(current) + && TRAITS::Equals(key, TRAITS::GetKey(current))) + { + return ¤t; + } + + if (increment == 0) + increment = (hash % (tableSize-1)) + 1; + + index += increment; + if (index >= tableSize) + index -= tableSize; + } + + } + + const element_t* LookupPtr(key_t key) const + { + return Lookup(m_table, m_tableSize, key); + } + + bool Add(const element_t &element) + { + if (!CheckGrowth()) + return false; + + if (Add(m_table, m_tableSize, element)) + m_tableOccupied++; + m_tableCount++; + + return true; + } + + bool CheckGrowth() + { + if (m_tableOccupied == m_tableMax) + { + return Grow(); + } + + return true; + } + + bool Reallocate(count_t newTableSize) + { + // ASSERT(newTableSize >= + // (count_t) (GetCount() * TRAITS::s_density_factor_denominator / TRAITS::s_density_factor_numerator)); + + // Allocation size must be a prime number. This is necessary so that hashes uniformly + // distribute to all indices, and so that chaining will visit all indices in the hash table. + newTableSize = NextPrime(newTableSize); + if (newTableSize == 0) + { + TRAITS::OnFailure(ftOverflow_EP); + return false; + } + + element_t *newTable = new (nothrow) element_t [newTableSize]; + if (newTable == NULL) + { + TRAITS::OnFailure(ftAllocation_EP); + return false; + } + + element_t *p = newTable, *pEnd = newTable + newTableSize; + while (p < pEnd) + { + *p = TRAITS::Null(); + p++; + } + + for (Iterator i = Begin(), end = End(); i != end; i++) + { + const element_t & cur = (*i); + if (!TRAITS::IsNull(cur) && !TRAITS::IsDeleted(cur)) + Add(newTable, newTableSize, cur); + } + + // @todo: + // We might want to try to delay this cleanup to allow asynchronous readers + + delete [] m_table; + + m_table = PTR_element_t(newTable); + m_tableSize = newTableSize; + m_tableMax = (count_t) (newTableSize * TRAITS::s_density_factor_numerator / TRAITS::s_density_factor_denominator); + m_tableOccupied = m_tableCount; + + return true; + } + + // + // Enumerator, provides a template to produce an iterator on an existing class + // with a single iteration variable. + // + + template + class Enumerator + { + private: + const SUBTYPE *This() const + { + return (const SUBTYPE *) this; + } + + SUBTYPE *This() + { + return (SUBTYPE *)this; + } + + public: + + Enumerator() + { + } + + const element_t &operator*() const + { + return This()->Get(); + } + const element_t *operator->() const + { + return &(This()->Get()); + } + SUBTYPE &operator++() + { + This()->Next(); + return *This(); + } + SUBTYPE operator++(int) + { + SUBTYPE i = *This(); + This()->Next(); + return i; + } + bool operator==(const SUBTYPE &i) const + { + return This()->Equal(i); + } + bool operator!=(const SUBTYPE &i) const + { + return !This()->Equal(i); + } + }; + + // + // Index for whole table iterator. This is also the base for the keyed iterator. + // + + class Index + { + friend class SHash_EP; + friend class Iterator; + friend class Enumerator; + + // The methods implementation has to be here for portability + // Some compilers won't compile the separate implementation in shash.inl + protected: + + PTR_element_t m_table; + count_t m_tableSize; + count_t m_index; + + Index(const SHash_EP *hash, bool begin) + : m_table(hash->m_table), + m_tableSize(hash->m_tableSize), + m_index(begin ? 0 : m_tableSize) + { + } + + const element_t &Get() const + { + return m_table[m_index]; + } + + void First() + { + if (m_index < m_tableSize) + if (TRAITS::IsNull(m_table[m_index]) || TRAITS::IsDeleted(m_table[m_index])) + Next(); + } + + void Next() + { + if (m_index >= m_tableSize) + return; + + for (;;) + { + m_index++; + if (m_index >= m_tableSize) + break; + if (!TRAITS::IsNull(m_table[m_index]) && !TRAITS::IsDeleted(m_table[m_index])) + break; + } + } + + bool Equal(const Index &i) const + { + return i.m_index == m_index; + } + }; + + + class Iterator : public Index, public Enumerator + { + friend class SHash_EP; + TRAITS* _t; + + public: + Iterator(const SHash_EP *hash, bool begin) + : Index(hash, begin) + { + } + }; + + Iterator Begin() const + { + Iterator i(this, true); + i.First(); + return i; + } + Iterator End() const + { + return Iterator(this, false); + } + + bool AddNoThrow(const element_t &element) + { + //PalDebugBreak(); + return false; + } + bool AddOrReplaceNoThrow(const element_t &element) + { + //PalDebugBreak(); + return false; + } + + count_t GetCount() const + { + return m_tableCount; + } + + void Remove(key_t key) + { + //PalDebugBreak(); + } + + // Remove the specific element. + void Remove(Iterator& i) + { + //PalDebugBreak(); + } + void RemoveAll() + { + delete [] m_table; + + m_table = NULL; + m_tableSize = 0; + m_tableCount = 0; + m_tableOccupied = 0; + m_tableMax = 0; + } + + // Instance members + private: + PTR_element_t m_table; // pointer to table + count_t m_tableSize; // allocated size of table + count_t m_tableCount; // number of elements in table + count_t m_tableOccupied; // number, includes deleted slots + count_t m_tableMax; // maximum occupied count before reallocating + + bool Grow() + { + count_t newSize = (count_t) (m_tableCount + * TRAITS::s_growth_factor_numerator / TRAITS::s_growth_factor_denominator + * TRAITS::s_density_factor_denominator / TRAITS::s_density_factor_numerator); + if (newSize < TRAITS::s_minimum_allocation) + newSize = TRAITS::s_minimum_allocation; + + // handle potential overflow + if (newSize < m_tableCount) + { + TRAITS::OnFailure(ftOverflow_EP); + return false; + } + + return Reallocate(newSize); + } + + static bool IsPrime(count_t number) + { + // This is a very low-tech check for primality, which doesn't scale very well. + // There are more efficient tests if this proves to be burdensome for larger + // tables. + + if ((number&1) == 0) + return false; + + count_t factor = 3; + while (factor * factor <= number) + { + if ((number % factor) == 0) + return false; + factor += 2; + } + + return true; + } + + static constexpr uint32_t g_shash_primes[] = { + 11,17,23,29,37,47,59,71,89,107,131,163,197,239,293,353,431,521,631,761,919, + 1103,1327,1597,1931,2333,2801,3371,4049,4861,5839,7013,8419,10103,12143,14591, + 17519,21023,25229,30293,36353,43627,52361,62851,75431,90523, 108631, 130363, + 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, + 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, + 4999559, 5999471, 7199369 }; + + // Returns a prime larger than 'number' or 0, in case of overflow + static count_t NextPrime(count_t number) + { + for (int i = 0; i < (int) (sizeof(g_shash_primes) / sizeof(g_shash_primes[0])); i++) + { + if (g_shash_primes[i] >= number) + return (typename SHash_EP::count_t)(g_shash_primes[i]); + } + + if ((number&1) == 0) + number++; + + while (number != 1) + { + if (IsPrime(number)) + return number; + number += 2; + } + + return 0; + } + + static bool Add(element_t *table, count_t tableSize, const element_t &element) + { + key_t key = TRAITS::GetKey(element); + + count_t hash = TRAITS::Hash(key); + count_t index = hash % tableSize; + count_t increment = 0; // delay computation + + while (true) + { + element_t& current = table[index]; + + if (TRAITS::IsNull(current)) + { + table[index] = element; + return true; + } + + if (TRAITS::IsDeleted(current)) + { + table[index] = element; + return false; + } + + if (increment == 0) + increment = (hash % (tableSize-1)) + 1; + + index += increment; + if (index >= tableSize) + index -= tableSize; + } + } + +}; + +template +class KeyValuePair_EP{ + KEY key; + VALUE value; + +public: + KeyValuePair_EP() + { + } + + KeyValuePair_EP(const KEY& k, const VALUE& v) + : key(k), value(v) + { + } + + KEY const & Key() const + { + return key; + } + + VALUE const & Value() const + { + return value; + } +}; + +template +class NoRemoveSHashTraits_EP : public PARENT +{ +public: + typedef typename PARENT::element_t element_t; + typedef typename PARENT::count_t count_t; +}; + +template +class MapSHashTraits_EP : public DefaultSHashTraits_EP< KeyValuePair_EP > +{ +public: + typedef typename DefaultSHashTraits_EP< KeyValuePair_EP >::element_t element_t; + typedef typename DefaultSHashTraits_EP< KeyValuePair_EP >::count_t count_t; + + typedef KEY key_t; + typedef VALUE value_t; + + static key_t GetKey(element_t e) + { + return e.Key(); + } + static bool Equals(key_t k1, key_t k2) + { + return k1 == k2; + } + static count_t Hash(key_t k) + { + return (count_t)(size_t)k; + } + + static const element_t Null() + { + return element_t(KEY(),VALUE()); + } + static bool IsNull(const element_t &e) + { + return e.Key() == KEY(); + } + static bool IsDeleted(const element_t &e) + { + return e.Key() == KEY(-1); + } + + key_t const & Key() const + { + //PalDebugBreak(); + return *(new KEY()); + } + + value_t const & Value() const + { + //PalDebugBreak(); + return *(new VALUE()); + } +}; + + +#endif // __EmptyContainers2_h__ diff --git a/src/coreclr/nativeaot/Runtime/EnabledEventPipeInterface.cpp b/src/coreclr/nativeaot/Runtime/EnabledEventPipeInterface.cpp new file mode 100644 index 0000000000000..a94cdd05d2d3a --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/EnabledEventPipeInterface.cpp @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "eventpipeadapter.h" +#include "diagnosticserveradapter.h" + +#include "gcenv.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "SpinLock.h" + +void EventPipeAdapter_Initialize() { EventPipeAdapter::Initialize(); } + +bool DiagnosticServerAdapter_Initialize() { return DiagnosticServerAdapter::Initialize(); } +void DiagnosticServerAdapter_PauseForDiagnosticsMonitor() { DiagnosticServerAdapter::PauseForDiagnosticsMonitor();} + + +void EventPipeAdapter_FinishInitialize() { EventPipeAdapter::FinishInitialize(); } + +void EventPipeAdapter_Shutdown() { EventPipeAdapter::Shutdown(); } +bool DiagnosticServerAdapter_Shutdown() { return DiagnosticServerAdapter::Shutdown(); } diff --git a/src/coreclr/nativeaot/Runtime/EventPipeInterface.h b/src/coreclr/nativeaot/Runtime/EventPipeInterface.h new file mode 100644 index 0000000000000..8015bc8f4c0c1 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/EventPipeInterface.h @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#ifndef __EVENTPIPE_INTERFACE_H__ +#define __EVENTPIPE_INTERFACE_H__ + +// Initialize EventPipe +void EventPipeAdapter_Initialize(); + +// Initialize DS +bool DiagnosticServerAdapter_Initialize(); +void DiagnosticServerAdapter_PauseForDiagnosticsMonitor(); + + +void EventPipeAdapter_FinishInitialize(); + +void EventPipeAdapter_Shutdown(); +bool DiagnosticServerAdapter_Shutdown(); + +#endif //__EVENTPIPE_INTERFACE_H__ \ No newline at end of file diff --git a/src/coreclr/nativeaot/Runtime/PalRedhawk.h b/src/coreclr/nativeaot/Runtime/PalRedhawk.h index 6b14fcb2b20cc..1ffbe94c41811 100644 --- a/src/coreclr/nativeaot/Runtime/PalRedhawk.h +++ b/src/coreclr/nativeaot/Runtime/PalRedhawk.h @@ -716,6 +716,7 @@ REDHAWK_PALIMPORT void* REDHAWK_PALAPI PalAddVectoredExceptionHandler(uint32_t f typedef uint32_t (__stdcall *BackgroundCallback)(_In_opt_ void* pCallbackContext); REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext); REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext); +REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext); typedef void (*PalHijackCallback)(_In_ NATIVE_CONTEXT* pThreadContext, _In_opt_ void* pThreadToHijack); REDHAWK_PALIMPORT void REDHAWK_PALAPI PalHijack(HANDLE hThread, _In_opt_ void* pThreadToHijack); diff --git a/src/coreclr/nativeaot/Runtime/diagnosticserveradapter.h b/src/coreclr/nativeaot/Runtime/diagnosticserveradapter.h new file mode 100644 index 0000000000000..62cd5816d08fd --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/diagnosticserveradapter.h @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __DIAGNOSTIC_SERVER_ADAPTER_H__ +#define __DIAGNOSTIC_SERVER_ADAPTER_H__ + +#if defined(FEATURE_PERFTRACING) + +#include + +class DiagnosticServerAdapter final +{ +public: + static inline bool Initialize() + { + return ds_server_init(); + } + + static inline bool Shutdown() + { + return ds_server_shutdown(); + } + + NOINLINE static void PauseForDiagnosticsMonitor() + { + return ds_server_pause_for_diagnostics_monitor(); + } + + static void ResumeRuntimeStartup() + { + return ds_server_resume_runtime_startup(); + } + + static bool IsPausedInRuntimeStartup() + { + return ds_server_is_paused_in_startup(); + } +}; + +#endif // FEATURE_PERFTRACING + +#endif // __DIAGNOSTIC_SERVER_ADAPTER_H__ diff --git a/src/coreclr/nativeaot/Runtime/disabledeventpipeinternal.cpp b/src/coreclr/nativeaot/Runtime/disabledeventpipeinternal.cpp new file mode 100644 index 0000000000000..b1464bdb22570 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/disabledeventpipeinternal.cpp @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "common.h" +#include "eventpipeadapter.h" + +#ifdef FEATURE_PERFTRACING + +#include "gcenv.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "SpinLock.h" + +struct EventPipeEventInstanceData; + +struct EventPipeSessionInfo; + +EXTERN_C NATIVEAOT_API uint64_t __cdecl RhEventPipeInternal_Enable( + LPCWSTR outputFile, + EventPipeSerializationFormat format, + uint32_t circularBufferSizeInMB, + /* COR_PRF_EVENTPIPE_PROVIDER_CONFIG */ const void * pProviders, + uint32_t numProviders) +{ + PalDebugBreak(); + return 0; +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_Disable(uint64_t sessionID) +{ + PalDebugBreak(); +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_CreateProvider( + LPCWSTR providerName, + EventPipeCallback pCallbackFunc, + void* pCallbackContext) +{ + return 0; +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_DefineEvent( + intptr_t provHandle, + uint32_t eventID, + int64_t keywords, + uint32_t eventVersion, + uint32_t level, + void *pMetadata, + uint32_t metadataLength) +{ + return 0; +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_GetProvider(LPCWSTR providerName) +{ + PalDebugBreak(); + return 0; +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_DeleteProvider(intptr_t provHandle) +{ +} + +EXTERN_C NATIVEAOT_API int __cdecl RhEventPipeInternal_EventActivityIdControl(uint32_t controlCode, GUID *pActivityId) +{ + PalDebugBreak(); + return 0; +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_WriteEventData( + intptr_t eventHandle, + EventData *pEventData, + uint32_t eventDataCount, + const GUID * pActivityId, + const GUID * pRelatedActivityId) +{ +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_GetSessionInfo(uint64_t sessionID, EventPipeSessionInfo *pSessionInfo) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_GetNextEvent(uint64_t sessionID, EventPipeEventInstanceData *pInstance) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_SignalSession(uint64_t sessionID) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_WaitForSessionSignal(uint64_t sessionID, int32_t timeoutMs) +{ + PalDebugBreak(); + return FALSE; +} + +#endif // FEATURE_PERFTRACING diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt new file mode 100644 index 0000000000000..39d658db4b18d --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/CMakeLists.txt @@ -0,0 +1,99 @@ +project(Runtime) + +set(EP_GENERATED_HEADER_PATH "${GENERATED_INCLUDE_DIR}") +include (${CLR_SRC_NATIVE_DIR}/eventpipe/configure.cmake) +include_directories(${EP_GENERATED_HEADER_PATH}) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(AOT_EVENTPIPE_SHIM_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +set (EVENTPIPE_SOURCES "") +set (EVENTPIPE_HEADERS "") +set (CORECLR_EVENTPIPE_SHIM_SOURCES "") +set (CORECLR_EVENTPIPE_SHIM_HEADERS "") + +set (SHARED_EVENTPIPE_SOURCE_PATH "${CLR_SRC_NATIVE_DIR}/eventpipe") +include (${SHARED_EVENTPIPE_SOURCE_PATH}/CMakeLists.txt) + +list(APPEND SHARED_DIAGNOSTIC_SERVER_SOURCES + ds-ipc-pal-namedpipe.c +) + +list(APPEND SHARED_DIAGNOSTIC_SERVER_HEADERS + ds-ipc-pal-namedpipe.h +) + +list(APPEND EVENTPIPE_SOURCES + ${SHARED_EVENTPIPE_SOURCES} + ${SHARED_DIAGNOSTIC_SERVER_SOURCES} +) + +list(APPEND EVENTPIPE_HEADERS + ${SHARED_EVENTPIPE_HEADERS} + ${SHARED_DIAGNOSTIC_SERVER_HEADERS} +) + +addprefix(EVENTPIPE_SOURCES ${SHARED_EVENTPIPE_SOURCE_PATH} "${EVENTPIPE_SOURCES}") +addprefix(EVENTPIPE_HEADERS ${SHARED_EVENTPIPE_SOURCE_PATH} "${EVENTPIPE_HEADERS}") + +set_source_files_properties(${SHARED_EVENTPIPE_SOURCE_PATH}/ep-sources.c PROPERTIES COMPILE_DEFINITIONS EP_FORCE_INCLUDE_SOURCE_FILES) +set_source_files_properties(${SHARED_EVENTPIPE_SOURCE_PATH}/ds-sources.c PROPERTIES COMPILE_DEFINITIONS DS_FORCE_INCLUDE_SOURCE_FILES) + +set_source_files_properties(${EVENTPIPE_SOURCES} PROPERTIES LANGUAGE CXX) + +if(CLR_CMAKE_HOST_UNIX) + if (CMAKE_VERSION VERSION_GREATER 3.11 OR CMAKE_VERSION VERSION_EQUAL 3.11) + set_source_files_properties(${EVENTPIPE_SOURCES} PROPERTIES COMPILE_OPTIONS -xc++) + else(CMAKE_VERSION VERSION_GREATER 3.11 OR CMAKE_VERSION VERSION_EQUAL 3.11) + add_compile_options(-xc++) + endif() +endif(CLR_CMAKE_HOST_UNIX) + +if (WIN32) + set_source_files_properties(${EVENTPIPE_SOURCES} PROPERTIES COMPILE_FLAGS "/FI\"${RUNTIME_DIR}/eventpipe/NativeaotEventPipeSupport.h\"") +endif() + +list(APPEND AOT_EVENTPIPE_SHIM_SOURCES + ${AOT_EVENTPIPE_SHIM_DIR}/ep-rt-aot.cpp +) + +list(APPEND AOT_EVENTPIPE_SHIM_HEADERS + ${AOT_EVENTPIPE_SHIM_DIR}/ds-rt-aot.h + ${AOT_EVENTPIPE_SHIM_DIR}/ds-rt-types-aot.h + ${AOT_EVENTPIPE_SHIM_DIR}/ep-rt-aot.h + ${AOT_EVENTPIPE_SHIM_DIR}/ep-rt-config-aot.h + ${AOT_EVENTPIPE_SHIM_DIR}/ep-rt-types-aot.h +) + +list(APPEND AOT_EVENTPIPE_MANAGED_TO_NATIVE_SOURCES + ${RUNTIME_DIR}/eventpipeinternal.cpp + ${RUNTIME_DIR}/eventpipeadapter.h + ${RUNTIME_DIR}/diagnosticserveradapter.h + ${RUNTIME_DIR}/EnabledEventPipeInterface.cpp +) + +list(APPEND EVENTPIPE_SOURCES + ${AOT_EVENTPIPE_SHIM_SOURCES} + ${AOT_EVENTPIPE_SHIM_HEADERS} + ${AOT_EVENTPIPE_MANAGED_TO_NATIVE_SOURCES} + ${SHARED_EVENTPIPE_CONFIG_HEADERS} +) + +list(APPEND AOT_EVENTPIPE_DISABLED_SOURCES + ${RUNTIME_DIR}/DisabledEventPipeInterface.cpp + ${RUNTIME_DIR}/disabledeventpipeinternal.cpp +) + +add_library(eventpipe-enabled STATIC ${EVENTPIPE_SOURCES}) +add_library(eventpipe-disabled STATIC ${AOT_EVENTPIPE_DISABLED_SOURCES}) + +if (CLR_CMAKE_TARGET_WIN32) + add_library(eventpipe-disabled.GuardCF STATIC ${AOT_EVENTPIPE_DISABLED_SOURCES}) + target_compile_options(eventpipe-disabled.GuardCF PRIVATE $<$,$>:/guard:cf>) +endif (CLR_CMAKE_TARGET_WIN32) + +install_static_library(eventpipe-enabled aotsdk nativeaot) +install_static_library(eventpipe-disabled aotsdk nativeaot) +if (CLR_CMAKE_TARGET_WIN32) + install_static_library(eventpipe-disabled.GuardCF aotsdk nativeaot) +endif (CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/NativeaotEventPipeSupport.h b/src/coreclr/nativeaot/Runtime/eventpipe/NativeaotEventPipeSupport.h new file mode 100644 index 0000000000000..253f147e32d99 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/NativeaotEventPipeSupport.h @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __NativeaotEventPipeSupport_h__ +#define __NativeaotEventPipeSupport_h__ + +// This file is included only when compiling shared EventPipe source files and contains any +// definitions which are needed by these source files but are not available in NativeAOT +// runtime source files. + +// As mentioned PalRedhawk*.cpp, in general we don't want to assume that Windows and +// Redhawk global definitions can co-exist, meaning NativeAOT runtime source files +// generally do not have access to windows.h; that said, the HOST_WIN32 parts of the shared +// EventPipe code are designed to rely on windows.h, so windows.h must be included when +// compiling shared EventPipe source files, and a marker is set to indicate that windows.h +// has been added to the compilation in this manner. + +#include + +#define BUILDING_SHARED_NATIVEAOT_EVENTPIPE_CODE + +#endif // __NativeaotEventPipeSupport_h__ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h new file mode 100644 index 0000000000000..8b09c8eb16e50 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h @@ -0,0 +1,319 @@ +// Implementation of ds-rt.h targeting AOT runtime. +#ifndef __DIAGNOSTICS_RT_AOT_H__ +#define __DIAGNOSTICS_RT_AOT_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-aot.h" +#include +#include +#include + +#undef DS_LOG_ALWAYS_0 +#define DS_LOG_ALWAYS_0(msg) do {} while (0) + +#undef DS_LOG_ALWAYS_1 +#define DS_LOG_ALWAYS_1(msg, data1) do {} while (0) + +#undef DS_LOG_ALWAYS_2 +#define DS_LOG_ALWAYS_2(msg, data1, data2) do {} while (0) + +#undef DS_LOG_INFO_0 +#define DS_LOG_INFO_0(msg) do {} while (0) + +#undef DS_LOG_INFO_1 +#define DS_LOG_INFO_1(msg, data1) do {} while (0) + +#undef DS_LOG_INFO_2 +#define DS_LOG_INFO_2(msg, data1, data2) do {} while (0) + +#undef DS_LOG_ERROR_0 +#define DS_LOG_ERROR_0(msg) do {} while (0) + +#undef DS_LOG_ERROR_1 +#define DS_LOG_ERROR_1(msg, data1) do {} while (0) + +#undef DS_LOG_ERROR_2 +#define DS_LOG_ERROR_2(msg, data1, data2) do {} while (0) + +#undef DS_LOG_WARNING_0 +#define DS_LOG_WARNING_0(msg) do {} while (0) + +#undef DS_LOG_WARNING_1 +#define DS_LOG_WARNING_1(msg, data1) do {} while (0) + +#undef DS_LOG_WARNING_2 +#define DS_LOG_WARNING_2(msg, data1, data2) do {} while (0) + +#undef DS_LOG_DEBUG_0 +#define DS_LOG_DEBUG_0(msg) do {} while (0) + +#undef DS_LOG_DEBUG_1 +#define DS_LOG_DEBUG_1(msg, data1) do {} while (0) + +#undef DS_LOG_DEBUG_2 +#define DS_LOG_DEBUG_2(msg, data1, data2) do {} while (0) + +#undef DS_ENTER_BLOCKING_PAL_SECTION +#define DS_ENTER_BLOCKING_PAL_SECTION + +#undef DS_EXIT_BLOCKING_PAL_SECTION +#define DS_EXIT_BLOCKING_PAL_SECTION + +#undef DS_RT_DEFINE_ARRAY +#define DS_RT_DEFINE_ARRAY(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_PREFIX(ds, array_name, array_type, iterator_type, item_type) + +#undef DS_RT_DEFINE_LOCAL_ARRAY +#define DS_RT_DEFINE_LOCAL_ARRAY(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_LOCAL_ARRAY_PREFIX(ds, array_name, array_type, iterator_type, item_type) + +#undef DS_RT_DEFINE_ARRAY_ITERATOR +#define DS_RT_DEFINE_ARRAY_ITERATOR(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_ITERATOR_PREFIX(ds, array_name, array_type, iterator_type, item_type) + +#undef DS_RT_DEFINE_ARRAY_REVERSE_ITERATOR +#define DS_RT_DEFINE_ARRAY_REVERSE_ITERATOR(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_REVERSE_ITERATOR_PREFIX(ds, array_name, array_type, iterator_type, item_type) + +/* +* AutoTrace. +*/ + +#ifdef FEATURE_AUTO_TRACE +#include "autotrace.h" +#endif + +static +void +ds_rt_auto_trace_init (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef FEATURE_AUTO_TRACE + auto_trace_init (); +#endif +} + +static +void +ds_rt_auto_trace_launch (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef FEATURE_AUTO_TRACE + auto_trace_launch (); +#endif +} + +static +void +ds_rt_auto_trace_signal (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef FEATURE_AUTO_TRACE + auto_trace_signal (); +#endif +} + +static +void +ds_rt_auto_trace_wait (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef FEATURE_AUTO_TRACE + auto_trace_wait (); +#endif +} + +/* + * DiagnosticsConfiguration. + */ + +static +inline +bool +ds_rt_config_value_get_enable (void) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + return true; +} + +static +inline +ep_char8_t * +ds_rt_config_value_get_ports (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + return nullptr; +} + +static +inline +uint32_t +ds_rt_config_value_get_default_port_suspend (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + return 0; +} + +/* +* DiagnosticsDump. +*/ + +static +ds_ipc_result_t +ds_rt_generate_core_dump ( + DiagnosticsDumpCommandId commandId, + DiagnosticsGenerateCoreDumpCommandPayload *payload, + ep_char8_t *errorMessageBuffer, + int32_t cbErrorMessageBuffer) +{ + STATIC_CONTRACT_NOTHROW; + + ds_ipc_result_t result = DS_IPC_E_FAIL; + uint32_t flags = ds_generate_core_dump_command_payload_get_flags(payload); + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Generate an exception dump + // PalDebugBreak(); + + return 0; +} + +/* + * DiagnosticsIpc. + */ + +static +inline +bool +ds_rt_transport_get_default_name ( + ep_char8_t *name, + int32_t name_len, + const ep_char8_t *prefix, + int32_t id, + const ep_char8_t *group_id, + const ep_char8_t *suffix) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: PAL_GetTransportName is defined in coreclr\pal\inc\pal.h + return true; +} + +/* + * DiagnosticsIpcPollHandle. + */ + +DS_RT_DEFINE_ARRAY (ipc_poll_handle_array, ds_rt_ipc_poll_handle_array_t, ds_rt_ipc_poll_handle_array_iterator_t, DiagnosticsIpcPollHandle) +DS_RT_DEFINE_LOCAL_ARRAY (ipc_poll_handle_array, ds_rt_ipc_poll_handle_array_t, ds_rt_ipc_poll_handle_array_iterator_t, DiagnosticsIpcPollHandle) +DS_RT_DEFINE_ARRAY_ITERATOR (ipc_poll_handle_array, ds_rt_ipc_poll_handle_array_t, ds_rt_ipc_poll_handle_array_iterator_t, DiagnosticsIpcPollHandle) + +#undef DS_RT_DECLARE_LOCAL_IPC_POLL_HANDLE_ARRAY +#define DS_RT_DECLARE_LOCAL_IPC_POLL_HANDLE_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ds_rt_ipc_poll_handle_array_t) + +/* + * DiagnosticsPort. + */ + +DS_RT_DEFINE_ARRAY (port_array, ds_rt_port_array_t, ds_rt_port_array_iterator_t, DiagnosticsPort *) +DS_RT_DEFINE_ARRAY_ITERATOR (port_array, ds_rt_port_array_t, ds_rt_port_array_iterator_t, DiagnosticsPort *) + +DS_RT_DEFINE_ARRAY (port_config_array, ds_rt_port_config_array_t, ds_rt_port_config_array_iterator_t, ep_char8_t *) +DS_RT_DEFINE_LOCAL_ARRAY (port_config_array, ds_rt_port_config_array_t, ds_rt_port_config_array_iterator_t, ep_char8_t *) +DS_RT_DEFINE_ARRAY_ITERATOR (port_config_array, ds_rt_port_config_array_t, ds_rt_port_config_array_iterator_t, ep_char8_t *) +DS_RT_DEFINE_ARRAY_REVERSE_ITERATOR (port_config_array, ds_rt_port_config_array_t, ds_rt_port_config_array_reverse_iterator_t, ep_char8_t *) + +#undef DS_RT_DECLARE_LOCAL_PORT_CONFIG_ARRAY +#define DS_RT_DECLARE_LOCAL_PORT_CONFIG_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ds_rt_port_config_array_t) + +/* +* DiagnosticsProfiler. +*/ +#ifdef PROFILING_SUPPORTED +#include "profilinghelper.h" +#include "profilinghelper.inl" + +#ifdef FEATURE_PROFAPI_ATTACH_DETACH +static +uint32_t +ds_rt_profiler_attach (DiagnosticsAttachProfilerCommandPayload *payload) +{ + STATIC_CONTRACT_NOTHROW; + + if (!g_profControlBlock.fProfControlBlockInitialized) + return DS_IPC_E_RUNTIME_UNINITIALIZED; + + // Certain actions are only allowable during attach, and this flag is how we track it. + ClrFlsSetThreadType (ThreadType_ProfAPI_Attach); + + HRESULT hr = S_OK; + hr = ProfilingAPIUtility::LoadProfilerForAttach (reinterpret_cast(ds_attach_profiler_command_payload_get_profiler_guid_cref (payload)), + reinterpret_cast(ds_attach_profiler_command_payload_get_profiler_path (payload)), + reinterpret_cast(ds_attach_profiler_command_payload_get_client_data (payload)), + static_cast(ds_attach_profiler_command_payload_get_client_data_len (payload)), + static_cast(ds_attach_profiler_command_payload_get_attach_timeout (payload))); + + // Clear the flag so this thread isn't permanently marked as the attach thread. + ClrFlsClearThreadType (ThreadType_ProfAPI_Attach); + + return hr; +} +#endif // FEATURE_PROFAPI_ATTACH_DETACH + +static +uint32_t +ds_rt_profiler_startup (DiagnosticsStartupProfilerCommandPayload *payload) +{ + STATIC_CONTRACT_NOTHROW; + + HRESULT hr = S_OK; + StoredProfilerNode *profilerData = new StoredProfilerNode(); + profilerData->guid = *(reinterpret_cast(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload))); + profilerData->path.Set(reinterpret_cast(ds_startup_profiler_command_payload_get_profiler_path (payload))); + + g_profControlBlock.storedProfilers.InsertHead(profilerData); + + return hr; +} +#endif // PROFILING_SUPPORTED + +static +uint32_t +ds_rt_set_environment_variable (const ep_char16_t *name, const ep_char16_t *value) +{ + // return SetEnvironmentVariableW(reinterpret_cast(name), reinterpret_cast(value)) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); + // PalDebugBreak(); + return 0xffff; +} + +/* +* DiagnosticServer. +*/ + +static +void +ds_rt_server_log_pause_message (void) +{ + STATIC_CONTRACT_NOTHROW; + + const char diagPortsName[] = "DOTNET_DiagnosticPorts"; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Cannot find nocache versions of RhConfig + // PalDebugBreak(); +} + +#endif /* ENABLE_PERFTRACING */ +#endif /* __DIAGNOSTICS_RT_AOT_H__ */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-types-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-types-aot.h new file mode 100644 index 0000000000000..9c01f9f6ff016 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-types-aot.h @@ -0,0 +1,40 @@ +// Implementation of ds-rt-types.h targeting CoreCLR runtime. +#ifndef __DIAGNOSTICS_RT_TYPES_AOT_H__ +#define __DIAGNOSTICS_RT_TYPES_AOT_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-types-aot.h" + +/* + * DiagnosticsIpcPollHandle. + */ + +#undef ds_rt_ipc_poll_handle_array_t +typedef struct _rt_aot_array_internal_t ds_rt_ipc_poll_handle_array_t; + +#undef ds_rt_ipc_poll_handle_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ds_rt_ipc_poll_handle_array_iterator_t; + +/* + * DiagnosticsPort. + */ + +#undef ds_rt_port_array_t +typedef struct _rt_aot_array_internal_t ds_rt_port_array_t; + +#undef ds_rt_port_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ds_rt_port_array_iterator_t; + +#undef ds_rt_port_config_array_t +typedef struct _rt_aot_array_internal_t ds_rt_port_config_array_t; + +#undef ds_rt_port_config_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ds_rt_port_config_array_iterator_t; + +#undef ds_rt_port_config_array_reverse_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ds_rt_port_config_array_reverse_iterator_t; + +#endif /* ENABLE_PERFTRACING */ +#endif /* __DIAGNOSTICS_RT_TYPES_AOT_H__ */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp new file mode 100644 index 0000000000000..ad1951fc100aa --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp @@ -0,0 +1,502 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include +#include +#include +#include + +// The regdisplay.h, StackFrameIterator.h, and thread.h includes are present only to access the Thread +// class and can be removed if it turns out that the required ep_rt_thread_handle_t can be +// implemented in some manner that doesn't rely on the Thread class. + +#include "gcenv.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "holder.h" +#include "SpinLock.h" + +ep_rt_lock_handle_t _ep_rt_aot_config_lock_handle; +CrstStatic _ep_rt_aot_config_lock; + +thread_local EventPipeAotThreadHolderTLS EventPipeAotThreadHolderTLS::g_threadHolderTLS; + +ep_char8_t *volatile _ep_rt_aot_diagnostics_cmd_line; + +#ifndef TARGET_UNIX +uint32_t *_ep_rt_aot_proc_group_offsets; +#endif + +/* + * Forward declares of all static functions. + */ + + +static +void +walk_managed_stack_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event); + + +bool +ep_rt_aot_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents) +{ + PalDebugBreak(); + return false; +} + +// The thread store lock must already be held by the thread before this function +// is called. ThreadSuspend::SuspendEE acquires the thread store lock. +static +void +walk_managed_stack_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ +} + +void +ep_rt_aot_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ +} + +const ep_char8_t * +ep_rt_aot_entrypoint_assembly_name_get_utf8 (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe assembly name - return filename in nativeaot? + PalDebugBreak(); + + // fallback to the empty string if we can't get assembly info, e.g., if the runtime is + // suspended before an assembly is loaded. + return reinterpret_cast(""); +} + +uint32_t +ep_rt_aot_atomic_inc_uint32_t (volatile uint32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + return static_cast(PalInterlockedIncrement ((volatile int32_t *)(value))); +} + +uint32_t +ep_rt_aot_atomic_dec_uint32_t (volatile uint32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + return static_cast(PalInterlockedDecrement ((volatile int32_t *)(value))); +} + +int32_t +ep_rt_aot_atomic_inc_int32_t (volatile int32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + return static_cast(PalInterlockedIncrement (value)); +} + +int32_t +ep_rt_aot_atomic_dec_int32_t (volatile int32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + return static_cast(PalInterlockedDecrement (value)); +} + +int64_t +ep_rt_aot_atomic_inc_int64_t (volatile int64_t *value) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Consider replacing with a new PalInterlockedIncrement64 service + int64_t currentValue; + do { + currentValue = *value; + } while (currentValue != PalInterlockedCompareExchange64(value, (currentValue + 1), currentValue)); + + // The current value has been atomically replaced with the incremented value. + return (currentValue + 1); +} + +int64_t +ep_rt_aot_atomic_dec_int64_t (volatile int64_t *value) { + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Consider replacing with a new PalInterlockedDecrement64 service + int64_t currentValue; + do { + currentValue = *value; + } while (currentValue != PalInterlockedCompareExchange64(value, (currentValue - 1), currentValue)); + + // The current value has been atomically replaced with the decremented value. + return (currentValue - 1); +} + +size_t +ep_rt_aot_atomic_compare_exchange_size_t (volatile size_t *target, size_t expected, size_t value) { + STATIC_CONTRACT_NOTHROW; +#ifdef HOST_64BIT + return static_cast(PalInterlockedCompareExchange64 ((volatile int64_t *)target, (int64_t)value, (int64_t)expected)); +#else + return static_cast(PalInterlockedCompareExchange ((volatile int32_t *)target, (int32_t)value, (int32_t)expected)); +#endif +} + +ep_char8_t * +ep_rt_aot_atomic_compare_exchange_utf8_string (ep_char8_t *volatile *target, ep_char8_t *expected, ep_char8_t *value) { + STATIC_CONTRACT_NOTHROW; + return static_cast(PalInterlockedCompareExchangePointer ((void *volatile *)target, value, expected)); +} + + +void +ep_rt_aot_wait_event_alloc ( + ep_rt_wait_event_handle_t *wait_event, + bool manual, + bool initial) +{ + STATIC_CONTRACT_NOTHROW; + + EP_ASSERT (wait_event != NULL); + EP_ASSERT (wait_event->event == NULL); + + wait_event->event = new (nothrow) CLREventStatic (); + if (wait_event->event) { + // NativeAOT has the NoThrow versions + if (manual) + wait_event->event->CreateManualEventNoThrow (initial); + else + wait_event->event->CreateAutoEventNoThrow (initial); + } +} + +void +ep_rt_aot_wait_event_free (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + + if (wait_event != NULL && wait_event->event != NULL) { + wait_event->event->CloseEvent (); + delete wait_event->event; + wait_event->event = NULL; + } +} + +bool +ep_rt_aot_wait_event_set (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (wait_event != NULL && wait_event->event != NULL); + + return wait_event->event->Set (); +} + +int32_t +ep_rt_aot_wait_event_wait ( + ep_rt_wait_event_handle_t *wait_event, + uint32_t timeout, + bool alertable) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (wait_event != NULL && wait_event->event != NULL); + + return wait_event->event->Wait (timeout, alertable); +} + +bool +ep_rt_aot_wait_event_is_valid (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + + if (wait_event == NULL || wait_event->event == NULL) + return false; + + return wait_event->event->IsValid (); +} + +/* + * Misc. + */ + +int +ep_rt_aot_get_last_error (void) +{ + STATIC_CONTRACT_NOTHROW; + return PalGetLastError(); +} + +bool +ep_rt_aot_thread_create ( + void *thread_func, + void *params, + EventPipeThreadType thread_type, + void *id) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (thread_func != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Fill in the outgoing id if any callers ever need it + if (id) + *reinterpret_cast(id) = 0xffffffff; + + switch (thread_type) + { + default: + return false; + + case EP_THREAD_TYPE_SERVER: + // Match CoreCLR and hardcode a null thread context in this case. + return PalStartEventPipeHelperThread(reinterpret_cast(thread_func), NULL); + + case EP_THREAD_TYPE_SESSION: + case EP_THREAD_TYPE_SAMPLING: + ep_rt_thread_params_t* thread_params = new (nothrow) ep_rt_thread_params_t (); + if (!thread_params) + return false; + + thread_params->thread_type = thread_type; + thread_params->thread_func = reinterpret_cast(thread_func); + thread_params->thread_params = params; + if (!PalStartEventPipeHelperThread(reinterpret_cast(ep_rt_thread_aot_start_session_or_sampling_thread), thread_params)) { + delete thread_params; + return false; + } + + return true; + } +} + +void +ep_rt_aot_thread_sleep (uint64_t ns) +{ + STATIC_CONTRACT_NOTHROW; + PalSleep(static_cast(ns/1000000)); +} + +uint32_t +ep_rt_aot_current_process_get_id (void) +{ + STATIC_CONTRACT_NOTHROW; + return static_cast(GetCurrentProcessId ()); +} + +ep_rt_thread_id_t +ep_rt_aot_current_thread_get_id (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef TARGET_UNIX + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: AOT doesn't have PAL_GetCurrentOSThreadId, as CoreCLR does. + // PalDebugBreak(); + return static_cast(0); +#else + return static_cast(::GetCurrentThreadId ()); +#endif +} + +int64_t +ep_rt_aot_perf_counter_query (void) +{ + STATIC_CONTRACT_NOTHROW; + return (int64_t)PalQueryPerformanceCounter(); +} + +int64_t +ep_rt_aot_perf_frequency_query (void) +{ + STATIC_CONTRACT_NOTHROW; + return (int64_t)PalQueryPerformanceFrequency(); +} + +int64_t +ep_rt_aot_system_timestamp_get (void) +{ + STATIC_CONTRACT_NOTHROW; + + FILETIME value; + GetSystemTimeAsFileTime (&value); + return static_cast(((static_cast(value.dwHighDateTime)) << 32) | static_cast(value.dwLowDateTime)); +} + +uint8_t * +ep_rt_aot_valloc0 (size_t buffer_size) +{ + STATIC_CONTRACT_NOTHROW; + return reinterpret_cast(PalVirtualAlloc (NULL, buffer_size, MEM_COMMIT, PAGE_READWRITE)); +} + +void +ep_rt_aot_vfree ( + uint8_t *buffer, + size_t buffer_size) +{ + STATIC_CONTRACT_NOTHROW; + + if (buffer) + PalVirtualFree (buffer, 0, MEM_RELEASE); +} + +void +ep_rt_aot_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + + spin_lock->lock = new (nothrow) SpinLock (); +} + +void +ep_rt_aot_spin_lock_free (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + + if (spin_lock && spin_lock->lock) { + delete spin_lock->lock; + spin_lock->lock = NULL; + } +} + +size_t +ep_rt_aot_utf16_string_len (const ep_char16_t *str) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (str != NULL); + + return wcslen (reinterpret_cast(str)); +} + +uint32_t +ep_rt_aot_volatile_load_uint32_t (const volatile uint32_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoad ((const uint32_t *)ptr); +} + +uint32_t +ep_rt_aot_volatile_load_uint32_t_without_barrier (const volatile uint32_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoadWithoutBarrier ((const uint32_t *)ptr); +} + +void +ep_rt_aot_volatile_store_uint32_t ( + volatile uint32_t *ptr, + uint32_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStore ((uint32_t *)ptr, value); +} + +void +ep_rt_aot_volatile_store_uint32_t_without_barrier ( + volatile uint32_t *ptr, + uint32_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStoreWithoutBarrier((uint32_t *)ptr, value); +} + +uint64_t +ep_rt_aot_volatile_load_uint64_t (const volatile uint64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoad ((const uint64_t *)ptr); +} + +uint64_t +ep_rt_aot_volatile_load_uint64_t_without_barrier (const volatile uint64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoadWithoutBarrier ((const uint64_t *)ptr); +} + +void +ep_rt_aot_volatile_store_uint64_t ( + volatile uint64_t *ptr, + uint64_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStore ((uint64_t *)ptr, value); +} + +void +ep_rt_aot_volatile_store_uint64_t_without_barrier ( + volatile uint64_t *ptr, + uint64_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStoreWithoutBarrier ((uint64_t *)ptr, value); +} + +int64_t +ep_rt_aot_volatile_load_int64_t (const volatile int64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoad ((int64_t *)ptr); +} + +int64_t +ep_rt_aot_volatile_load_int64_t_without_barrier (const volatile int64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoadWithoutBarrier ((int64_t *)ptr); +} + +void +ep_rt_aot_volatile_store_int64_t ( + volatile int64_t *ptr, + int64_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStore ((int64_t *)ptr, value); +} + +void +ep_rt_aot_volatile_store_int64_t_without_barrier ( + volatile int64_t *ptr, + int64_t value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStoreWithoutBarrier ((int64_t *)ptr, value); +} + +void * +ep_rt_aot_volatile_load_ptr (volatile void **ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoad ((void **)ptr); +} + +void * +ep_rt_aot_volatile_load_ptr_without_barrier (volatile void **ptr) +{ + STATIC_CONTRACT_NOTHROW; + return VolatileLoadWithoutBarrier ((void **)ptr); +} + +void +ep_rt_aot_volatile_store_ptr ( + volatile void **ptr, + void *value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStore ((void **)ptr, value); +} + +void +ep_rt_aot_volatile_store_ptr_without_barrier ( + volatile void **ptr, + void *value) +{ + STATIC_CONTRACT_NOTHROW; + VolatileStoreWithoutBarrier ((void **)ptr, value); +} + +#endif /* ENABLE_PERFTRACING */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h new file mode 100644 index 0000000000000..5c6f8ab834dc0 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h @@ -0,0 +1,3145 @@ +// Implementation of ep-rt.h targeting CoreCLR runtime. +#ifndef __EVENTPIPE_RT_AOT_H__ +#define __EVENTPIPE_RT_AOT_H__ + +#include // For isspace + +#include +#ifdef ENABLE_PERFTRACING +#include +#include +#include +#include + +#include "rhassert.h" + +#ifdef TARGET_UNIX +#define sprintf_s snprintf +#define _stricmp strcasecmp +#define INFINITE 0xFFFFFFFF // Infinite timeout +#endif + +#define STATIC_CONTRACT_NOTHROW + +#undef EP_INFINITE_WAIT +#define EP_INFINITE_WAIT INFINITE + +#undef EP_GCX_PREEMP_ENTER +#define EP_GCX_PREEMP_ENTER { //GCX_PREEMP(); + +#undef EP_GCX_PREEMP_EXIT +#define EP_GCX_PREEMP_EXIT } + +#undef EP_ALWAYS_INLINE +#define EP_ALWAYS_INLINE + +#undef EP_NEVER_INLINE +#define EP_NEVER_INLINE + +#undef EP_ALIGN_UP +#define EP_ALIGN_UP(val,align) _rt_aot_align_up(val,align) + +// shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase +// TODO: The NativeAOT ALIGN_UP is defined in a tangled manner that generates linker errors if +// it is used here; instead, define a version tailored to the existing usage in the shared +// EventPipe code. +static inline uint8_t* _rt_aot_align_up(uint8_t* val, uintptr_t alignment) +{ + // alignment must be a power of 2 for this implementation to work (need modulo otherwise) + EP_ASSERT( 0 == (alignment & (alignment - 1)) ); + uintptr_t rawVal = reinterpret_cast(val); + uintptr_t result = (rawVal + (alignment - 1)) & ~(alignment - 1); + EP_ASSERT( result >= rawVal ); // check for overflow + return reinterpret_cast(result); +} + +#ifndef EP_RT_BUILD_TYPE_FUNC_NAME +#define EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, type_name, func_name) \ +prefix_name ## _rt_ ## type_name ## _ ## func_name +#endif + +template +static +inline +void +_rt_aot_list_alloc (LIST_TYPE *list) { + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL); + + list->list = new (nothrow) typename LIST_TYPE::list_type_t (); +} + +template +static +inline +void +_rt_aot_list_free ( + LIST_TYPE *list, + void (*callback)(void *)) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL); + + if (list->list) { + while (!list->list->IsEmpty ()) { + typename LIST_TYPE::element_type_t *current = list->list->RemoveHead (); + if (callback) + callback (reinterpret_cast(current->GetValue ())); + delete current; + } + delete list->list; + } + list->list = NULL; +} + +template +static +inline +void +_rt_aot_list_clear ( + LIST_TYPE *list, + void (*callback)(void *)) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL); + + while (!list->list->IsEmpty ()) { + typename LIST_TYPE::element_type_t *current = list->list->RemoveHead (); + if (callback) + callback (reinterpret_cast(current->GetValue ())); + delete current; + } +} + +template +static +inline +bool +_rt_aot_list_append ( + LIST_TYPE *list, + LIST_ITEM item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL); + + typename LIST_TYPE::element_type_t *node = new (nothrow) typename LIST_TYPE::element_type_t (item); + if (node) + list->list->InsertTail (node); + return (node != NULL); +} + +template +static +inline +void +_rt_aot_list_remove ( + LIST_TYPE *list, + CONST_LIST_ITEM item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL); + + typename LIST_TYPE::element_type_t *current = list->list->GetHead (); + while (current) { + if (current->GetValue () == item) { + if (list->list->FindAndRemove (current)) + delete current; + break; + } + current = list->list->GetNext (current); + } +} + +template +static +inline +bool +_rt_aot_list_find ( + CONST_LIST_TYPE *list, + CONST_LIST_ITEM item_to_find, + LIST_ITEM *found_item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL); + EP_ASSERT (found_item != NULL); + + bool found = false; + typename LIST_TYPE::element_type_t *current = list->list->GetHead (); + while (current) { + if (current->GetValue () == item_to_find) { + *found_item = current->GetValue (); + found = true; + break; + } + current = list->list->GetNext (current); + } + return found; +} + +template +static +inline +bool +_rt_aot_list_is_empty (CONST_LIST_TYPE *list) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL); + + return (list->list == NULL || list->list->IsEmpty ()); +} + +template +static +inline +bool +_rt_aot_list_is_valid (CONST_LIST_TYPE *list) +{ + STATIC_CONTRACT_NOTHROW; + return (list != NULL && list->list != NULL); +} + +template +static +inline +ITERATOR_TYPE +_rt_aot_list_iterator_begin (CONST_LIST_TYPE *list) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL); + + return list->list->begin (); +} + +template +static +inline +bool +_rt_aot_list_iterator_end ( + CONST_LIST_TYPE *list, + CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (list != NULL && list->list != NULL && iterator != NULL); + + return (*iterator == list->list->end ()); +} + +template +static +inline +void +_rt_aot_list_iterator_next (ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL); + + (*iterator)++; +} + +template +static +inline +ITEM_TYPE +_rt_aot_list_iterator_value (CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL); + + return const_cast(iterator)->operator*(); +} + +template +static +inline +void +_rt_aot_queue_alloc (QUEUE_TYPE *queue) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL); + + queue->queue = new (nothrow) typename QUEUE_TYPE::queue_type_t (); +} + +template +static +inline +void +_rt_aot_queue_free (QUEUE_TYPE *queue) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL); + + if (queue->queue) + delete queue->queue; + queue->queue = NULL; +} + +template +static +inline +bool +_rt_aot_queue_pop_head ( + QUEUE_TYPE *queue, + ITEM_TYPE *item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL && queue->queue != NULL && item != NULL); + + bool found = true; + typename QUEUE_TYPE::element_type_t *node = queue->queue->RemoveHead (); + if (node) { + *item = node->m_Value; + delete node; + } else { + *item = NULL; + found = false; + } + return found; +} + +template +static +inline +bool +_rt_aot_queue_push_head ( + QUEUE_TYPE *queue, + ITEM_TYPE item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL && queue->queue != NULL); + + typename QUEUE_TYPE::element_type_t *node = new (nothrow) typename QUEUE_TYPE::element_type_t (item); + if (node) + queue->queue->InsertHead (node); + return (node != NULL); +} + +template +static +inline +bool +_rt_aot_queue_push_tail ( + QUEUE_TYPE *queue, + ITEM_TYPE item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL && queue->queue != NULL); + + typename QUEUE_TYPE::element_type_t *node = new (nothrow) typename QUEUE_TYPE::element_type_t (item); + if (node) + queue->queue->InsertTail (node); + return (node != NULL); +} + +template +static +inline +bool +_rt_aot_queue_is_empty (CONST_QUEUE_TYPE *queue) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (queue != NULL && queue->queue != NULL); + + return (queue->queue != NULL && queue->queue->IsEmpty ()); +} + +template +static +inline +bool +_rt_aot_queue_is_valid (CONST_QUEUE_TYPE *queue) +{ + STATIC_CONTRACT_NOTHROW; + return (queue != NULL && queue->queue != NULL); +} + +template +static +inline +void +_rt_aot_array_alloc (ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL); + + ep_array->array = new (nothrow) typename ARRAY_TYPE::array_type_t (); +} + +template +static +inline +void +_rt_aot_array_alloc_capacity ( + ARRAY_TYPE *ep_array, + size_t capacity) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL); + + ep_array->array = new (nothrow) typename ARRAY_TYPE::array_type_t (); + if (ep_array->array) + ep_array->array->AllocNoThrow (capacity); +} + +template +static +inline +void +_rt_aot_array_init_capacity ( + ARRAY_TYPE *ep_array, + size_t capacity) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL); + + if (ep_array->array) + ep_array->array->AllocNoThrow (capacity); +} + +template +static +inline +void +_rt_aot_array_free (ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL); + + if (ep_array->array) { + delete ep_array->array; + ep_array->array = NULL; + } +} + +template +static +inline +bool +_rt_aot_array_append ( + ARRAY_TYPE *ep_array, + ITEM_TYPE item) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + return ep_array->array->PushNoThrow (item); +} + +template +static +inline +void +_rt_aot_array_clear (ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + while (ep_array->array->Size () > 0) + ITEM_TYPE item = ep_array->array->Pop (); + ep_array->array->Shrink (); +} + +template +static +inline +size_t +_rt_aot_array_size (CONST_ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + return ep_array->array->Size (); +} + +template +static +inline +ITEM_TYPE * +_rt_aot_array_data (CONST_ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + return ep_array->array->Ptr (); +} + +template +static +inline +bool +_rt_aot_array_is_valid (CONST_ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + return (ep_array->array != NULL); +} + +template +static +inline +ITERATOR_TYPE +_rt_aot_array_iterator_begin (CONST_ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + ITERATOR_TYPE temp; + temp.array = ep_array->array; + temp.index = 0; + return temp; +} + +template +static +inline +bool +_rt_aot_array_iterator_end ( + CONST_ARRAY_TYPE *ep_array, + CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && iterator != NULL && iterator->array != NULL); + + return (iterator->index >= static_cast(iterator->array->Size ())); +} + +template +static +inline +void +_rt_aot_array_iterator_next (ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL); + + iterator->index++; +} + +template +static +inline +ITEM_TYPE +_rt_aot_array_iterator_value (const CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL && iterator->array != NULL); + EP_ASSERT (iterator->index < static_cast(iterator->array->Size ())); + + return iterator->array->operator[] (iterator->index); +} + +template +static +inline +ITERATOR_TYPE +_rt_aot_array_reverse_iterator_begin (CONST_ARRAY_TYPE *ep_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && ep_array->array != NULL); + + ITERATOR_TYPE temp; + temp.array = ep_array->array; + temp.index = static_cast(ep_array->array->Size ()); + return temp; +} + +template +static +inline +bool +_rt_aot_array_reverse_iterator_end ( + CONST_ARRAY_TYPE *ep_array, + CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_array != NULL && iterator != NULL && iterator->array != NULL); + + return (iterator->index == 0); +} + +template +static +inline +void +_rt_aot_array_reverse_iterator_next (ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL); + + iterator->index--; +} + +template +static +inline +ITEM_TYPE +_rt_aot_array_reverse_iterator_value (CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (iterator != NULL && iterator->array != NULL); + EP_ASSERT (iterator->index > 0); + + return iterator->array->operator[] (iterator->index - 1); +} + +template +static +inline +void +_rt_aot_hash_map_alloc ( + HASH_MAP_TYPE *hash_map, + uint32_t (*hash_callback)(const void *), + bool (*eq_callback)(const void *, const void *), + void (*key_free_callback)(void *), + void (*value_free_callback)(void *)) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && key_free_callback == NULL); + + hash_map->table = new (nothrow) typename HASH_MAP_TYPE::table_type_t (); + hash_map->callbacks.key_free_func = key_free_callback; + hash_map->callbacks.value_free_func = value_free_callback; +} + +template +static +inline +void +_rt_aot_hash_map_free (HASH_MAP_TYPE *hash_map) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL); + + if (hash_map->table) { + if (hash_map->callbacks.value_free_func) { + for (typename HASH_MAP_TYPE::table_type_t::Iterator iterator = hash_map->table->Begin (); iterator != hash_map->table->End (); ++iterator) + hash_map->callbacks.value_free_func (reinterpret_cast((ptrdiff_t)(iterator->Value ()))); + } + delete hash_map->table; + } +} + +template +static +inline +bool +_rt_aot_hash_map_add ( + HASH_MAP_TYPE *hash_map, + KEY_TYPE key, + VALUE_TYPE value) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + return hash_map->table->Add (typename HASH_MAP_TYPE::table_type_t::element_t (key, value)); +} + +template +static +inline +bool +_rt_aot_hash_map_add_or_replace ( + HASH_MAP_TYPE *hash_map, + KEY_TYPE key, + VALUE_TYPE value) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + return hash_map->table->AddOrReplaceNoThrow (typename HASH_MAP_TYPE::table_type_t::element_t (key, value)); +} + +template +static +inline +void +_rt_aot_hash_map_remove_all (HASH_MAP_TYPE *hash_map) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + if (hash_map->callbacks.value_free_func) { + for (typename HASH_MAP_TYPE::table_type_t::Iterator iterator = hash_map->table->Begin (); iterator != hash_map->table->End (); ++iterator) + hash_map->callbacks.value_free_func (reinterpret_cast((ptrdiff_t)(iterator->Value ()))); + } + hash_map->table->RemoveAll (); +} + +template +static +inline +bool +_rt_aot_hash_map_lookup ( + CONST_HASH_MAP_TYPE *hash_map, + CONST_KEY_TYPE key, + VALUE_TYPE *value) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + const typename HASH_MAP_TYPE::table_type_t::element_t *ret = hash_map->table->LookupPtr ((KEY_TYPE)key); + if (ret == NULL) + return false; + *value = ret->Value (); + return true; +} + +template +static +inline +uint32_t +_rt_aot_hash_map_count (CONST_HASH_MAP_TYPE *hash_map) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + return hash_map->table->GetCount (); +} + +template +static +inline +bool +_rt_aot_hash_map_is_valid (CONST_HASH_MAP_TYPE *hash_map) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + + return (hash_map != NULL && hash_map->table != NULL); +} + +template +static +inline +void +_rt_aot_hash_map_remove ( + HASH_MAP_TYPE *hash_map, + CONST_KEY_TYPE key) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + const typename HASH_MAP_TYPE::table_type_t::element_t *ret = NULL; + if (hash_map->callbacks.value_free_func) + ret = hash_map->table->LookupPtr ((KEY_TYPE)key); + hash_map->table->Remove ((KEY_TYPE)key); + if (ret) + hash_map->callbacks.value_free_func (reinterpret_cast(static_cast(ret->Value ()))); +} + +template +static +inline +ITERATOR_TYPE +_rt_aot_hash_map_iterator_begin (CONST_HASH_MAP_TYPE *hash_map) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL); + + return hash_map->table->Begin (); +} + +template +static +inline +bool +_rt_aot_hash_map_iterator_end ( + CONST_HASH_MAP_TYPE *hash_map, + CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (hash_map != NULL && hash_map->table != NULL && iterator != NULL); + + return (hash_map->table->End () == *iterator); +} + +template +static +inline +void +_rt_aot_hash_map_iterator_next (ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (iterator != NULL); + + (*iterator)++; +} + +template +static +inline +KEY_TYPE +_rt_aot_hash_map_iterator_key (CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (iterator != NULL); + + return (*iterator)->Key (); +} + +template +static +inline +VALUE_TYPE +_rt_aot_hash_map_iterator_value (CONST_ITERATOR_TYPE *iterator) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (HASH_MAP_TYPE::table_type_t::s_NoThrow); + EP_ASSERT (iterator != NULL); + + return (*iterator)->Value (); +} + +#define EP_RT_DEFINE_LIST_PREFIX(prefix_name, list_name, list_type, item_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, alloc) (list_type *list) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_list_alloc(list); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, free) (list_type *list, void (*callback)(void *)) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_list_free(list, callback); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, clear) (list_type *list, void (*callback)(void *)) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_list_clear(list, callback); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, append) (list_type *list, item_type item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_append(list, item); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, remove) (list_type *list, const item_type item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_list_remove(list, item); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, find) (const list_type *list, const item_type item_to_find, item_type *found_item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_find(list, item_to_find, found_item); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, is_empty) (const list_type *list) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_is_empty(list); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, is_valid) (const list_type *list) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_is_valid(list); \ + } + +#undef EP_RT_DEFINE_LIST +#define EP_RT_DEFINE_LIST(list_name, list_type, item_type) \ + EP_RT_DEFINE_LIST_PREFIX(ep, list_name, list_type, item_type) + +#define EP_RT_DEFINE_LIST_ITERATOR_PREFIX(prefix_name, list_name, list_type, iterator_type, item_type) \ + static inline iterator_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, iterator_begin) (const list_type *list) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_iterator_begin(list); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, iterator_end) (const list_type *list, const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_iterator_end(list, iterator); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, iterator_next) (iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_list_iterator_next(iterator); \ + } \ + static inline item_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, list_name, iterator_value) (const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_list_iterator_value(iterator); \ + } + +#undef EP_RT_DEFINE_LIST_ITERATOR +#define EP_RT_DEFINE_LIST_ITERATOR(list_name, list_type, iterator_type, item_type) \ + EP_RT_DEFINE_LIST_ITERATOR_PREFIX(ep, list_name, list_type, iterator_type, item_type) + +#define EP_RT_DEFINE_QUEUE_PREFIX(prefix_name, queue_name, queue_type, item_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, alloc) (queue_type *queue) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_queue_alloc(queue); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, free) (queue_type *queue) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_queue_free(queue); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, pop_head) (queue_type *queue, item_type *item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_queue_pop_head(queue, item); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, push_head) (queue_type *queue, item_type item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_queue_push_head(queue, item); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, push_tail) (queue_type *queue, item_type item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_queue_push_tail(queue, item); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, is_empty) (const queue_type *queue) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_queue_is_empty(queue); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, queue_name, is_valid) (const queue_type *queue) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_queue_is_valid(queue); \ + } + +#undef EP_RT_DEFINE_QUEUE +#define EP_RT_DEFINE_QUEUE(queue_name, queue_type, item_type) \ + EP_RT_DEFINE_QUEUE_PREFIX(ep, queue_name, queue_type, item_type) + +#define EP_RT_DEFINE_ARRAY_PREFIX(prefix_name, array_name, array_type, iterator_type, item_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, alloc) (array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_alloc(ep_array); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, alloc_capacity) (array_type *ep_array, size_t capacity) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_alloc_capacity(ep_array, capacity); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, free) (array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_free(ep_array); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, append) (array_type *ep_array, item_type item) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_append (ep_array, item); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, clear) (array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_clear (ep_array); \ + } \ + static inline size_t EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, size) (const array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_size (ep_array); \ + } \ + static inline item_type * EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, data) (const array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_data (ep_array); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, is_valid) (const array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_is_valid (ep_array); \ + } + +#define EP_RT_DEFINE_LOCAL_ARRAY_PREFIX(prefix_name, array_name, array_type, iterator_type, item_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, init) (array_type *ep_array) { \ + STATIC_CONTRACT_NOTHROW; \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, init_capacity) (array_type *ep_array, size_t capacity) { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_init_capacity(ep_array, capacity); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, fini) (array_type *ep_array) { \ + STATIC_CONTRACT_NOTHROW; \ + } + +#undef EP_RT_DEFINE_ARRAY +#define EP_RT_DEFINE_ARRAY(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_PREFIX(ep, array_name, array_type, iterator_type, item_type) + +#undef EP_RT_DEFINE_LOCAL_ARRAY +#define EP_RT_DEFINE_LOCAL_ARRAY(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_LOCAL_ARRAY_PREFIX(ep, array_name, array_type, iterator_type, item_type) + +#define EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, var_type) \ + var_type::array_type_t _local_ ##var_name; \ + var_type var_name; \ + var_name.array = &_local_ ##var_name + +#define EP_RT_DEFINE_ARRAY_ITERATOR_PREFIX(prefix_name, array_name, array_type, iterator_type, item_type) \ + static inline iterator_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, iterator_begin) (const array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_iterator_begin (ep_array); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, iterator_end) (const array_type *ep_array, const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_iterator_end (ep_array, iterator); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, iterator_next) (iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_iterator_next (iterator); \ + } \ + static inline item_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, iterator_value) (const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_iterator_value (iterator); \ + } + +#define EP_RT_DEFINE_ARRAY_REVERSE_ITERATOR_PREFIX(prefix_name, array_name, array_type, iterator_type, item_type) \ + static inline iterator_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, reverse_iterator_begin) (const array_type *ep_array) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_reverse_iterator_begin (ep_array); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, reverse_iterator_end) (const array_type *ep_array, const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_reverse_iterator_end (ep_array, iterator); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, reverse_iterator_next) (iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_array_reverse_iterator_next (iterator); \ + } \ + static inline item_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, array_name, reverse_iterator_value) (const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_array_reverse_iterator_value (iterator); \ + } + +#undef EP_RT_DEFINE_ARRAY_ITERATOR +#define EP_RT_DEFINE_ARRAY_ITERATOR(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_ITERATOR_PREFIX(ep, array_name, array_type, iterator_type, item_type) + +#undef EP_RT_DEFINE_ARRAY_REVERSE_ITERATOR +#define EP_RT_DEFINE_ARRAY_REVERSE_ITERATOR(array_name, array_type, iterator_type, item_type) \ + EP_RT_DEFINE_ARRAY_REVERSE_ITERATOR_PREFIX(ep, array_name, array_type, iterator_type, item_type) + +#define EP_RT_DEFINE_HASH_MAP_BASE_PREFIX(prefix_name, hash_map_name, hash_map_type, key_type, value_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, alloc) (hash_map_type *hash_map, uint32_t (*hash_callback)(const void *), bool (*eq_callback)(const void *, const void *), void (*key_free_callback)(void *), void (*value_free_callback)(void *)) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_hash_map_alloc(hash_map, hash_callback, eq_callback, key_free_callback, value_free_callback); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, free) (hash_map_type *hash_map) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_hash_map_free(hash_map); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, add) (hash_map_type *hash_map, key_type key, value_type value) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_add(hash_map, key, value); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, remove_all) (hash_map_type *hash_map) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_hash_map_remove_all(hash_map); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, lookup) (const hash_map_type *hash_map, const key_type key, value_type *value) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_lookup(hash_map, key, value); \ + } \ + static inline uint32_t EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, count) (const hash_map_type *hash_map) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_count(hash_map); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, is_valid) (const hash_map_type *hash_map) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_is_valid(hash_map); \ + } + +#define EP_RT_DEFINE_HASH_MAP_PREFIX(prefix_name, hash_map_name, hash_map_type, key_type, value_type) \ + EP_RT_DEFINE_HASH_MAP_BASE_PREFIX(prefix_name, hash_map_name, hash_map_type, key_type, value_type) \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, add_or_replace) (hash_map_type *hash_map, key_type key, value_type value) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_add_or_replace(hash_map, key, value); \ + } \ + +#define EP_RT_DEFINE_HASH_MAP_REMOVE_PREFIX(prefix_name, hash_map_name, hash_map_type, key_type, value_type) \ + EP_RT_DEFINE_HASH_MAP_BASE_PREFIX(prefix_name, hash_map_name, hash_map_type, key_type, value_type) \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, remove) (hash_map_type *hash_map, const key_type key) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_hash_map_remove(hash_map, key); \ + } + +#undef EP_RT_DEFINE_HASH_MAP +#define EP_RT_DEFINE_HASH_MAP(hash_map_name, hash_map_type, key_type, value_type) \ + EP_RT_DEFINE_HASH_MAP_PREFIX(ep, hash_map_name, hash_map_type, key_type, value_type) + +#undef EP_RT_DEFINE_HASH_MAP_REMOVE +#define EP_RT_DEFINE_HASH_MAP_REMOVE(hash_map_name, hash_map_type, key_type, value_type) \ + EP_RT_DEFINE_HASH_MAP_REMOVE_PREFIX(ep, hash_map_name, hash_map_type, key_type, value_type) + +#define EP_RT_DEFINE_HASH_MAP_ITERATOR_PREFIX(prefix_name, hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ + static inline iterator_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, iterator_begin) (const hash_map_type *hash_map) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_iterator_begin(hash_map); \ + } \ + static inline bool EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, iterator_end) (const hash_map_type *hash_map, const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_iterator_end(hash_map, iterator); \ + } \ + static inline void EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, iterator_next) (iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + _rt_aot_hash_map_iterator_next(iterator); \ + } \ + static inline key_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, iterator_key) (const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_iterator_key(iterator); \ + } \ + static inline value_type EP_RT_BUILD_TYPE_FUNC_NAME(prefix_name, hash_map_name, iterator_value) (const iterator_type *iterator) \ + { \ + STATIC_CONTRACT_NOTHROW; \ + return _rt_aot_hash_map_iterator_value(iterator); \ + } + +#undef EP_RT_DEFINE_HASH_MAP_ITERATOR +#define EP_RT_DEFINE_HASH_MAP_ITERATOR(hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ + EP_RT_DEFINE_HASH_MAP_ITERATOR_PREFIX(ep, hash_map_name, hash_map_type, iterator_type, key_type, value_type) + +static +inline +ep_rt_lock_handle_t * +ep_rt_aot_config_lock_get (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + return nullptr; +} + +static +inline +const ep_char8_t * +ep_rt_entrypoint_assembly_name_get_utf8 (void) +{ + STATIC_CONTRACT_NOTHROW; + + extern const ep_char8_t * ep_rt_aot_entrypoint_assembly_name_get_utf8 (void); + return ep_rt_aot_entrypoint_assembly_name_get_utf8(); +} + +static +const ep_char8_t * +ep_rt_runtime_version_get_utf8 (void) { + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Find a way to use CoreCLR runtime_version.h here if a more exact version is needed + return reinterpret_cast("8.0.0"); +} + +/* + * Little-Endian Conversion. + */ + +static +inline +uint16_t +ep_rt_val_uint16_t (uint16_t value) +{ + return value; +} + +static +inline +uint32_t +ep_rt_val_uint32_t (uint32_t value) +{ + return value; +} + +static +inline +uint64_t +ep_rt_val_uint64_t (uint64_t value) +{ + return value; +} + +static +inline +int16_t +ep_rt_val_int16_t (int16_t value) +{ + return value; +} + +static +inline +int32_t +ep_rt_val_int32_t (int32_t value) +{ + return value; +} + +static +inline +int64_t +ep_rt_val_int64_t (int64_t value) +{ + return value; +} + +static +inline +uintptr_t +ep_rt_val_uintptr_t (uintptr_t value) +{ + return value; +} + +/* +* Atomics. +*/ + +static +inline +uint32_t +ep_rt_atomic_inc_uint32_t (volatile uint32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + extern uint32_t ep_rt_aot_atomic_inc_uint32_t (volatile uint32_t *value); + return ep_rt_aot_atomic_inc_uint32_t (value); +} + +static +inline +uint32_t +ep_rt_atomic_dec_uint32_t (volatile uint32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + extern uint32_t ep_rt_aot_atomic_dec_uint32_t (volatile uint32_t *value); + return ep_rt_aot_atomic_dec_uint32_t (value); +} + +static +inline +int32_t +ep_rt_atomic_inc_int32_t (volatile int32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + extern int32_t ep_rt_aot_atomic_inc_int32_t (volatile int32_t *value); + + return ep_rt_aot_atomic_inc_int32_t (value); +} + +static +inline +int32_t +ep_rt_atomic_dec_int32_t (volatile int32_t *value) +{ + STATIC_CONTRACT_NOTHROW; + extern int32_t ep_rt_aot_atomic_dec_int32_t (volatile int32_t *value); + return ep_rt_aot_atomic_dec_int32_t (value); +} + +static +inline +int64_t +ep_rt_atomic_inc_int64_t (volatile int64_t *value) +{ + STATIC_CONTRACT_NOTHROW; + + extern int64_t ep_rt_aot_atomic_inc_int64_t (volatile int64_t *value); + return ep_rt_aot_atomic_inc_int64_t (value); +} + +static +inline +int64_t +ep_rt_atomic_dec_int64_t (volatile int64_t *value) +{ + STATIC_CONTRACT_NOTHROW; + + extern int64_t ep_rt_aot_atomic_dec_int64_t (volatile int64_t *value); + return ep_rt_aot_atomic_dec_int64_t (value); +} + +static +inline +size_t +ep_rt_atomic_compare_exchange_size_t (volatile size_t *target, size_t expected, size_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern size_t ep_rt_aot_atomic_compare_exchange_size_t (volatile size_t *target, size_t expected, size_t value); + return ep_rt_aot_atomic_compare_exchange_size_t (target, expected, value); +} + +static +inline +ep_char8_t * +ep_rt_atomic_compare_exchange_utf8_string (ep_char8_t *volatile *target, ep_char8_t *expected, ep_char8_t *value) +{ + STATIC_CONTRACT_NOTHROW; + extern ep_char8_t * ep_rt_aot_atomic_compare_exchange_utf8_string (ep_char8_t *volatile *target, ep_char8_t *expected, ep_char8_t *value); + return ep_rt_aot_atomic_compare_exchange_utf8_string (target, expected, value); +} + +/* + * EventPipe. + */ + +EP_RT_DEFINE_ARRAY (session_id_array, ep_rt_session_id_array_t, ep_rt_session_id_array_iterator_t, EventPipeSessionID) +EP_RT_DEFINE_ARRAY_ITERATOR (session_id_array, ep_rt_session_id_array_t, ep_rt_session_id_array_iterator_t, EventPipeSessionID) + +EP_RT_DEFINE_ARRAY (execution_checkpoint_array, ep_rt_execution_checkpoint_array_t, ep_rt_execution_checkpoint_array_iterator_t, EventPipeExecutionCheckpoint *) +EP_RT_DEFINE_ARRAY_ITERATOR (execution_checkpoint_array, ep_rt_execution_checkpoint_array_t, ep_rt_execution_checkpoint_array_iterator_t, EventPipeExecutionCheckpoint *) + +static +void +ep_rt_init (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT +} + +static +inline +void +ep_rt_init_finish (void) +{ + STATIC_CONTRACT_NOTHROW; +} + +static +inline +void +ep_rt_shutdown (void) +{ + STATIC_CONTRACT_NOTHROW; +} + +static +inline +bool +ep_rt_config_acquire (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + return true; +} + +static +inline +bool +ep_rt_config_release (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + return true; +} + +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_config_requires_lock_held (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + return; +} + +static +inline +void +ep_rt_config_requires_lock_not_held (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + return; +} +#endif + +static +inline +bool +ep_rt_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents) +{ + STATIC_CONTRACT_NOTHROW; + extern bool ep_rt_aot_walk_managed_stack_for_thread (ep_rt_thread_handle_t thread, EventPipeStackContents *stack_contents); + return ep_rt_aot_walk_managed_stack_for_thread (thread, stack_contents); +} + +static +inline +bool +ep_rt_method_get_simple_assembly_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Design MethodDesc and method name services if/when needed + //PalDebugBreak(); + + return false; + +} + +static +bool +ep_rt_method_get_full_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Design MethodDesc and method name services if/when needed + //PalDebugBreak(); + + return false; +} + +static +inline +void +ep_rt_provider_config_init (EventPipeProviderConfiguration *provider_config) +{ + STATIC_CONTRACT_NOTHROW; +} + +// This function is auto-generated from /src/scripts/genEventPipe.py +#ifdef TARGET_UNIX +extern "C" void InitProvidersAndEvents (); +#else +extern void InitProvidersAndEvents (); +#endif + +static +void +ep_rt_init_providers_and_events (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: auto-generated fn, no op for now + // InitProvidersAndEvents (); +} + +static +inline +bool +ep_rt_providers_validate_all_disabled (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context and MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context are not available in NativeAOT + return true; +} + +static +inline +void +ep_rt_prepare_provider_invoke_callback (EventPipeProviderCallbackData *provider_callback_data) +{ + STATIC_CONTRACT_NOTHROW; +} + +static +void +ep_rt_provider_invoke_callback ( + EventPipeCallback callback_func, + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_data) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (callback_func != NULL); + + (*callback_func)( + source_id, + is_enabled, + level, + match_any_keywords, + match_all_keywords, + filter_data, + callback_data); +} + +/* + * EventPipeBuffer. + */ + +EP_RT_DEFINE_ARRAY (buffer_array, ep_rt_buffer_array_t, ep_rt_buffer_array_iterator_t, EventPipeBuffer *) +EP_RT_DEFINE_LOCAL_ARRAY (buffer_array, ep_rt_buffer_array_t, ep_rt_buffer_array_iterator_t, EventPipeBuffer *) +EP_RT_DEFINE_ARRAY_ITERATOR (buffer_array, ep_rt_buffer_array_t, ep_rt_buffer_array_iterator_t, EventPipeBuffer *) + +#undef EP_RT_DECLARE_LOCAL_BUFFER_ARRAY +#define EP_RT_DECLARE_LOCAL_BUFFER_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ep_rt_buffer_array_t) + +/* + * EventPipeBufferList. + */ + +EP_RT_DEFINE_ARRAY (buffer_list_array, ep_rt_buffer_list_array_t, ep_rt_buffer_list_array_iterator_t, EventPipeBufferList *) +EP_RT_DEFINE_LOCAL_ARRAY (buffer_list_array, ep_rt_buffer_list_array_t, ep_rt_buffer_list_array_iterator_t, EventPipeBufferList *) +EP_RT_DEFINE_ARRAY_ITERATOR (buffer_list_array, ep_rt_buffer_list_array_t, ep_rt_buffer_list_array_iterator_t, EventPipeBufferList *) + +#undef EP_RT_DECLARE_LOCAL_BUFFER_LIST_ARRAY +#define EP_RT_DECLARE_LOCAL_BUFFER_LIST_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ep_rt_buffer_list_array_t) + +/* + * EventPipeEvent. + */ + +EP_RT_DEFINE_LIST (event_list, ep_rt_event_list_t, EventPipeEvent *) +EP_RT_DEFINE_LIST_ITERATOR (event_list, ep_rt_event_list_t, ep_rt_event_list_iterator_t, EventPipeEvent *) + +/* + * EventPipeFile. + */ + +EP_RT_DEFINE_HASH_MAP_REMOVE(metadata_labels_hash, ep_rt_metadata_labels_hash_map_t, EventPipeEvent *, uint32_t) +EP_RT_DEFINE_HASH_MAP(stack_hash, ep_rt_stack_hash_map_t, StackHashKey *, StackHashEntry *) +EP_RT_DEFINE_HASH_MAP_ITERATOR(stack_hash, ep_rt_stack_hash_map_t, ep_rt_stack_hash_map_iterator_t, StackHashKey *, StackHashEntry *) + +/* + * EventPipeProvider. + */ + +EP_RT_DEFINE_LIST (provider_list, ep_rt_provider_list_t, EventPipeProvider *) +EP_RT_DEFINE_LIST_ITERATOR (provider_list, ep_rt_provider_list_t, ep_rt_provider_list_iterator_t, EventPipeProvider *) + +EP_RT_DEFINE_QUEUE (provider_callback_data_queue, ep_rt_provider_callback_data_queue_t, EventPipeProviderCallbackData *) + +static +EventPipeProvider * +ep_rt_provider_list_find_by_name ( + const ep_rt_provider_list_t *list, + const ep_char8_t *name) +{ + STATIC_CONTRACT_NOTHROW; + + // The provider list should be non-NULL, but can be NULL on shutdown. + if (list) { + SList_EP> *provider_list = list->list; + SListElem_EP *element = provider_list->GetHead (); + while (element) { + EventPipeProvider *provider = element->GetValue (); + if (ep_rt_utf8_string_compare (ep_provider_get_provider_name (element->GetValue ()), name) == 0) + return provider; + + element = provider_list->GetNext (element); + } + } + + return NULL; +} + +/* + * EventPipeProviderConfiguration. + */ + +EP_RT_DEFINE_ARRAY (provider_config_array, ep_rt_provider_config_array_t, ep_rt_provider_config_array_iterator_t, EventPipeProviderConfiguration) +EP_RT_DEFINE_ARRAY_ITERATOR (provider_config_array, ep_rt_provider_config_array_t, ep_rt_provider_config_array_iterator_t, EventPipeProviderConfiguration) + +static +inline +bool +ep_rt_config_value_get_enable (void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EnableEventPipe) != 0 + // If EventPipe environment variables are specified, parse them and start a session. + // TODO: Not start a session for now + return false; +} + +static +inline +ep_char8_t * +ep_rt_config_value_get_config (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EventPipeConfig) + // PalDebugBreak(); + return nullptr; +// return ep_rt_utf16_to_utf8_string (reinterpret_cast(value.GetValue ()), -1); +} + +static +inline +ep_char8_t * +ep_rt_config_value_get_output_path (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EventPipeOutputPath) + //PalDebugBreak(); + return nullptr; +} + +static +inline +uint32_t +ep_rt_config_value_get_circular_mb (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EventPipeCircularMB) + //PalDebugBreak(); + return 0; +} + +static +inline +bool +ep_rt_config_value_get_output_streaming (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EventPipeOutputStreaming) + //PalDebugBreak(); + return false; +} + +/* + * EventPipeSampleProfiler. + */ + +static +inline +void +ep_rt_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ + STATIC_CONTRACT_NOTHROW; + + extern void ep_rt_aot_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event); + ep_rt_aot_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); +} + +static +inline +void +ep_rt_notify_profiler_provider_created (EventPipeProvider *provider) +{ + // Following mono's path of no-op +} + +/* + * EventPipeSessionProvider. + */ + +EP_RT_DEFINE_LIST (session_provider_list, ep_rt_session_provider_list_t, EventPipeSessionProvider *) +EP_RT_DEFINE_LIST_ITERATOR (session_provider_list, ep_rt_session_provider_list_t, ep_rt_session_provider_list_iterator_t, EventPipeSessionProvider *) + +static +EventPipeSessionProvider * +ep_rt_session_provider_list_find_by_name ( + const ep_rt_session_provider_list_t *list, + const ep_char8_t *name) +{ + STATIC_CONTRACT_NOTHROW; + + SList_EP> *provider_list = list->list; + EventPipeSessionProvider *session_provider = NULL; + SListElem_EP *element = provider_list->GetHead (); + while (element) { + EventPipeSessionProvider *candidate = element->GetValue (); + if (ep_rt_utf8_string_compare (ep_session_provider_get_provider_name (candidate), name) == 0) { + session_provider = candidate; + break; + } + element = provider_list->GetNext (element); + } + + return session_provider; +} + +/* + * EventPipeSequencePoint. + */ + +EP_RT_DEFINE_LIST (sequence_point_list, ep_rt_sequence_point_list_t, EventPipeSequencePoint *) +EP_RT_DEFINE_LIST_ITERATOR (sequence_point_list, ep_rt_sequence_point_list_t, ep_rt_sequence_point_list_iterator_t, EventPipeSequencePoint *) + +/* + * EventPipeThread. + */ + +EP_RT_DEFINE_LIST (thread_list, ep_rt_thread_list_t, EventPipeThread *) +EP_RT_DEFINE_LIST_ITERATOR (thread_list, ep_rt_thread_list_t, ep_rt_thread_list_iterator_t, EventPipeThread *) + +EP_RT_DEFINE_ARRAY (thread_array, ep_rt_thread_array_t, ep_rt_thread_array_iterator_t, EventPipeThread *) +EP_RT_DEFINE_LOCAL_ARRAY (thread_array, ep_rt_thread_array_t, ep_rt_thread_array_iterator_t, EventPipeThread *) +EP_RT_DEFINE_ARRAY_ITERATOR (thread_array, ep_rt_thread_array_t, ep_rt_thread_array_iterator_t, EventPipeThread *) + +#undef EP_RT_DECLARE_LOCAL_THREAD_ARRAY +#define EP_RT_DECLARE_LOCAL_THREAD_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ep_rt_thread_array_t) + +/* + * EventPipeThreadSessionState. + */ + +EP_RT_DEFINE_LIST (thread_session_state_list, ep_rt_thread_session_state_list_t, EventPipeThreadSessionState *) +EP_RT_DEFINE_LIST_ITERATOR (thread_session_state_list, ep_rt_thread_session_state_list_t, ep_rt_thread_session_state_list_iterator_t, EventPipeThreadSessionState *) + +EP_RT_DEFINE_ARRAY (thread_session_state_array, ep_rt_thread_session_state_array_t, ep_rt_thread_session_state_array_iterator_t, EventPipeThreadSessionState *) +EP_RT_DEFINE_LOCAL_ARRAY (thread_session_state_array, ep_rt_thread_session_state_array_t, ep_rt_thread_session_state_array_iterator_t, EventPipeThreadSessionState *) +EP_RT_DEFINE_ARRAY_ITERATOR (thread_session_state_array, ep_rt_thread_session_state_array_t, ep_rt_thread_session_state_array_iterator_t, EventPipeThreadSessionState *) + +#undef EP_RT_DECLARE_LOCAL_THREAD_SESSION_STATE_ARRAY +#define EP_RT_DECLARE_LOCAL_THREAD_SESSION_STATE_ARRAY(var_name) \ + EP_RT_DECLARE_LOCAL_ARRAY_VARIABLE(var_name, ep_rt_thread_session_state_array_t) + +/* + * Arrays. + */ + +static +inline +uint8_t * +ep_rt_byte_array_alloc (size_t len) +{ + STATIC_CONTRACT_NOTHROW; + return new (nothrow) uint8_t [len]; +} + +static +inline +void +ep_rt_byte_array_free (uint8_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + + if (ptr) + delete [] ptr; +} + +/* + * Event. + */ + +static +void +ep_rt_wait_event_alloc ( + ep_rt_wait_event_handle_t *wait_event, + bool manual, + bool initial) +{ + STATIC_CONTRACT_NOTHROW; + + extern void ep_rt_aot_wait_event_alloc ( + ep_rt_wait_event_handle_t *wait_event, + bool manual, + bool initial); + ep_rt_aot_wait_event_alloc(wait_event, manual, initial); +} + +static +inline +void +ep_rt_wait_event_free (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + extern void ep_rt_aot_wait_event_free (ep_rt_wait_event_handle_t *wait_event); + ep_rt_aot_wait_event_free(wait_event); +} + +static +inline +bool +ep_rt_wait_event_set (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + extern bool ep_rt_aot_wait_event_set (ep_rt_wait_event_handle_t *wait_event); + return ep_rt_aot_wait_event_set (wait_event); +} + +static +int32_t +ep_rt_wait_event_wait ( + ep_rt_wait_event_handle_t *wait_event, + uint32_t timeout, + bool alertable) +{ + STATIC_CONTRACT_NOTHROW; + extern int32_t +ep_rt_aot_wait_event_wait ( + ep_rt_wait_event_handle_t *wait_event, + uint32_t timeout, + bool alertable); + + return ep_rt_aot_wait_event_wait(wait_event, timeout, alertable); +} + +static +inline +EventPipeWaitHandle +ep_rt_wait_event_get_wait_handle (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + // EP_ASSERT (wait_event != NULL && wait_event->event != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: NativeAOT CLREventStatic doesn't have GetHandleUNHOSTED + // PalDebugBreak(); + return 0; +} + +static +inline +bool +ep_rt_wait_event_is_valid (ep_rt_wait_event_handle_t *wait_event) +{ + STATIC_CONTRACT_NOTHROW; + extern bool + ep_rt_aot_wait_event_is_valid (ep_rt_wait_event_handle_t *wait_event); + + return ep_rt_aot_wait_event_is_valid (wait_event); +} + +/* + * Misc. + */ + +static +inline +int +ep_rt_get_last_error (void) +{ + STATIC_CONTRACT_NOTHROW; + extern int + ep_rt_aot_get_last_error (void); + return ep_rt_aot_get_last_error (); +} + +static +inline +bool +ep_rt_process_detach (void) +{ + STATIC_CONTRACT_NOTHROW; + + return false; +} + +static +inline +bool +ep_rt_process_shutdown (void) +{ + STATIC_CONTRACT_NOTHROW; + + return false; +} + +static +inline +void +ep_rt_create_activity_id ( + uint8_t *activity_id, + uint32_t activity_id_len) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement a way to generate a real Guid + // CoCreateGuid (reinterpret_cast(activity_id)); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Using roughly Mono's implementation but Mono randomly generates this, hardcoding for now + uint8_t data1[] = {0x67,0xac,0x33,0xf1,0x8d,0xed,0x41,0x01,0xb4,0x26,0xc9,0xb7,0x94,0x35,0xf7,0x8a}; + memcpy (activity_id, data1, EP_ACTIVITY_ID_SIZE); + + const uint16_t version_mask = 0xF000; + const uint16_t random_guid_version = 0x4000; + const uint8_t clock_seq_hi_and_reserved_mask = 0xC0; + const uint8_t clock_seq_hi_and_reserved_value = 0x80; + + // Modify bits indicating the type of the GUID + uint8_t *activity_id_c = activity_id + sizeof (uint32_t) + sizeof (uint16_t); + uint8_t *activity_id_d = activity_id + sizeof (uint32_t) + sizeof (uint16_t) + sizeof (uint16_t); + + uint16_t c; + memcpy (&c, activity_id_c, sizeof (c)); + + uint8_t d; + memcpy (&d, activity_id_d, sizeof (d)); + + // time_hi_and_version + c = ((c & ~version_mask) | random_guid_version); + // clock_seq_hi_and_reserved + d = ((d & ~clock_seq_hi_and_reserved_mask) | clock_seq_hi_and_reserved_value); + + memcpy (activity_id_c, &c, sizeof (c)); + memcpy (activity_id_d, &d, sizeof (d)); +} + +static +inline +bool +ep_rt_is_running (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Does NativeAot have the concept of EEStarted + // PalDebugBreak(); + + return false; +} + +static +inline +void +ep_rt_execute_rundown (ep_rt_execution_checkpoint_array_t *execution_checkpoints) +{ + STATIC_CONTRACT_NOTHROW; + + //TODO: Write execution checkpoint rundown events. + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: EventPipe Configuration values - RhConfig? + // (CLRConfig::INTERNAL_EventPipeCircularMB) + // PalDebugBreak(); +} + +/* + * Objects. + */ + +// STATIC_CONTRACT_NOTHROW +#undef ep_rt_object_alloc +#define ep_rt_object_alloc(obj_type) (new (nothrow) obj_type()) + +// STATIC_CONTRACT_NOTHROW +#undef ep_rt_object_array_alloc +#define ep_rt_object_array_alloc(obj_type,size) (new (nothrow) obj_type [size]()) + +// STATIC_CONTRACT_NOTHROW +#undef ep_rt_object_array_free +#define ep_rt_object_array_free(obj_ptr) do { if (obj_ptr) delete [] obj_ptr; } while(0) + +// STATIC_CONTRACT_NOTHROW +#undef ep_rt_object_free +#define ep_rt_object_free(obj_ptr) do { if (obj_ptr) delete obj_ptr; } while(0) + +/* + * PAL. + */ + +#undef EP_RT_DEFINE_THREAD_FUNC +#define EP_RT_DEFINE_THREAD_FUNC(name) static ep_rt_thread_start_func_return_t __stdcall name (void *data) + +EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_aot_start_session_or_sampling_thread) +{ + STATIC_CONTRACT_NOTHROW; + + ep_rt_thread_params_t* thread_params = reinterpret_cast(data); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed. + // The session and sampling threads both assert that the incoming thread handle is + // non-null, but do not necessarily rely on it otherwise; just pass a meaningless non-null + // value until testing shows that a meaningful value is needed. + thread_params->thread = reinterpret_cast(1); + + size_t result = thread_params->thread_func (thread_params); + delete thread_params; + return result; +} + +static +bool +ep_rt_thread_create ( + void *thread_func, + void *params, + EventPipeThreadType thread_type, + void *id) +{ + STATIC_CONTRACT_NOTHROW; + extern bool + ep_rt_aot_thread_create ( + void *thread_func, + void *params, + EventPipeThreadType thread_type, + void *id); + + return ep_rt_aot_thread_create(thread_func, params, thread_type, id); +} + +static +inline +void +ep_rt_set_server_name(void) +{ + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Need to set name for the thread + // ::SetThreadName(GetCurrentThread(), W(".NET EventPipe")); +} + + +static +inline +void +ep_rt_thread_sleep (uint64_t ns) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_thread_sleep (uint64_t ns); + ep_rt_aot_thread_sleep(ns); +} + +static +inline +uint32_t +ep_rt_current_process_get_id (void) +{ + STATIC_CONTRACT_NOTHROW; + extern uint32_t + ep_rt_aot_current_process_get_id (void); + return ep_rt_aot_current_process_get_id(); +} + +static +inline +uint32_t +ep_rt_current_processor_get_number (void) +{ + STATIC_CONTRACT_NOTHROW; + +#ifndef TARGET_UNIX + extern uint32_t *_ep_rt_aot_proc_group_offsets; + if (_ep_rt_aot_proc_group_offsets) { + // PROCESSOR_NUMBER proc; + // GetCurrentProcessorNumberEx (&proc); + // return _ep_rt_aot_proc_group_offsets [proc.Group] + proc.Number; + // PalDebugBreak(); + } +#endif + return 0xFFFFFFFF; +} + +static +inline +uint32_t +ep_rt_processors_get_count (void) +{ + STATIC_CONTRACT_NOTHROW; +#ifdef _INC_WINDOWS + SYSTEM_INFO sys_info = {}; + GetSystemInfo (&sys_info); + return static_cast(sys_info.dwNumberOfProcessors); +#else + // PalDebugBreak(); + return 0xffff; +#endif +} + +static +inline +ep_rt_thread_id_t +ep_rt_current_thread_get_id (void) +{ + STATIC_CONTRACT_NOTHROW; + extern ep_rt_thread_id_t + ep_rt_aot_current_thread_get_id (void); + return ep_rt_aot_current_thread_get_id(); +} + +static +inline +int64_t +ep_rt_perf_counter_query (void) +{ + STATIC_CONTRACT_NOTHROW; + extern int64_t + ep_rt_aot_perf_counter_query (void); + + return ep_rt_aot_perf_counter_query(); +} + +static +inline +int64_t +ep_rt_perf_frequency_query (void) +{ + STATIC_CONTRACT_NOTHROW; + extern int64_t + ep_rt_aot_perf_frequency_query (void); + + return ep_rt_aot_perf_frequency_query(); +} + +static +inline +void +ep_rt_system_time_get (EventPipeSystemTime *system_time) +{ + STATIC_CONTRACT_NOTHROW; + +#ifdef _INC_WINDOWS + SYSTEMTIME value; + GetSystemTime (&value); + + EP_ASSERT(system_time != NULL); + ep_system_time_set ( + system_time, + value.wYear, + value.wMonth, + value.wDayOfWeek, + value.wDay, + value.wHour, + value.wMinute, + value.wSecond, + value.wMilliseconds); +#else + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Get System time + // PalDebugBreak(); +#endif + +} + +static +inline +int64_t +ep_rt_system_timestamp_get (void) +{ + STATIC_CONTRACT_NOTHROW; + extern int64_t ep_rt_aot_system_timestamp_get (void); + return ep_rt_aot_system_timestamp_get(); +} + +static +inline +int32_t +ep_rt_system_get_alloc_granularity (void) +{ + STATIC_CONTRACT_NOTHROW; + // return static_cast(g_SystemInfo.dwAllocationGranularity); + return 0x10000; +} + +static +inline +const ep_char8_t * +ep_rt_os_command_line_get (void) +{ + STATIC_CONTRACT_NOTHROW; + //EP_UNREACHABLE ("Can not reach here"); + + return NULL; +} + +static +ep_rt_file_handle_t +ep_rt_file_open_write (const ep_char8_t *path) +{ + STATIC_CONTRACT_NOTHROW; + + ep_char16_t *path_utf16 = ep_rt_utf8_to_utf16le_string (path, -1); + ep_return_null_if_nok (path_utf16 != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Find out the way to open a file in native + // PalDebugBreak(); + + return 0; +} + +static +inline +bool +ep_rt_file_close (ep_rt_file_handle_t file_handle) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Find out the way to close a file in native + // PalDebugBreak(); + return true; +} + +static +inline +bool +ep_rt_file_write ( + ep_rt_file_handle_t file_handle, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (buffer != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Find out the way to write to a file in native + // PalDebugBreak(); + + return false; +} + +static +inline +uint8_t * +ep_rt_valloc0 (size_t buffer_size) +{ + STATIC_CONTRACT_NOTHROW; + extern uint8_t * + ep_rt_aot_valloc0 (size_t buffer_size); + + return ep_rt_aot_valloc0(buffer_size); +} + +static +inline +void +ep_rt_vfree ( + uint8_t *buffer, + size_t buffer_size) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_vfree ( + uint8_t *buffer, + size_t buffer_size); + + return ep_rt_aot_vfree(buffer, buffer_size); +} + +static +inline +uint32_t +ep_rt_temp_path_get ( + ep_char8_t *buffer, + uint32_t buffer_len) +{ + STATIC_CONTRACT_NOTHROW; +// EP_UNREACHABLE ("Can not reach here"); + + return 0; +} + +EP_RT_DEFINE_ARRAY (env_array_utf16, ep_rt_env_array_utf16_t, ep_rt_env_array_utf16_iterator_t, ep_char16_t *) +EP_RT_DEFINE_ARRAY_ITERATOR (env_array_utf16, ep_rt_env_array_utf16_t, ep_rt_env_array_utf16_iterator_t, ep_char16_t *) + +static +void +ep_rt_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (env_array != NULL); + + // PalDebugBreak(); +} + +/* +* Lock. +*/ + +static +bool +ep_rt_lock_acquire (ep_rt_lock_handle_t *lock) +{ + STATIC_CONTRACT_NOTHROW; + + bool result = true; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + + return result; +} + +static +bool +ep_rt_lock_release (ep_rt_lock_handle_t *lock) +{ + STATIC_CONTRACT_NOTHROW; + + bool result = true; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement EventPipe locking for NativeAOT + + return result; +} + +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_lock_requires_lock_held (const ep_rt_lock_handle_t *lock) +{ + + STATIC_CONTRACT_NOTHROW; + //EP_ASSERT (((ep_rt_lock_handle_t *)lock)->lock->OwnedByCurrentThread ()); +} + +static +inline +void +ep_rt_lock_requires_lock_not_held (const ep_rt_lock_handle_t *lock) +{ + STATIC_CONTRACT_NOTHROW; + //EP_ASSERT (lock->lock == NULL || !((ep_rt_lock_handle_t *)lock)->lock->OwnedByCurrentThread ()); +} +#endif + +/* +* SpinLock. +*/ + +static +void +ep_rt_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock); + ep_rt_aot_spin_lock_alloc(spin_lock); +} + +static +inline +void +ep_rt_spin_lock_free (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_spin_lock_free (ep_rt_spin_lock_handle_t *spin_lock); + ep_rt_aot_spin_lock_free(spin_lock); +} + +static +inline +bool +ep_rt_spin_lock_acquire (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; +// EP_ASSERT (ep_rt_spin_lock_is_valid (spin_lock)); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement locking (maybe by making the manual Lock and Unlock functions public) + // SpinLock::Lock (*(spin_lock->lock)); + return true; +} + +static +inline +bool +ep_rt_spin_lock_release (ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_rt_spin_lock_is_valid (spin_lock)); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement locking (maybe by making the manual Lock and Unlock functions public) + // SpinLock::Unlock (*(spin_lock->lock)); + return true; +} + +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_spin_lock_requires_lock_held (const ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (ep_rt_spin_lock_is_valid (spin_lock)); + +} + +static +inline +void +ep_rt_spin_lock_requires_lock_not_held (const ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + +} +#endif + +static +inline +bool +ep_rt_spin_lock_is_valid (const ep_rt_spin_lock_handle_t *spin_lock) +{ + STATIC_CONTRACT_NOTHROW; + return (spin_lock != NULL && spin_lock->lock != NULL); +} + +/* + * String. + */ + +static +inline +int +ep_rt_utf8_string_compare ( + const ep_char8_t *str1, + const ep_char8_t *str2) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (str1 != NULL && str2 != NULL); + + return strcmp (reinterpret_cast(str1), reinterpret_cast(str2)); +} + +static +inline +int +ep_rt_utf8_string_compare_ignore_case ( + const ep_char8_t *str1, + const ep_char8_t *str2) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (str1 != NULL && str2 != NULL); + + return _stricmp (reinterpret_cast(str1), reinterpret_cast(str2)); +} + +static +inline +bool +ep_rt_utf8_string_is_null_or_empty (const ep_char8_t *str) +{ + STATIC_CONTRACT_NOTHROW; + + if (str == NULL) + return true; + + while (*str) { + if (!isspace (*str)) + return false; + str++; + } + return true; +} + +static +inline +ep_char8_t * +ep_rt_utf8_string_dup (const ep_char8_t *str) +{ + STATIC_CONTRACT_NOTHROW; + + if (!str) + return NULL; + +#ifdef TARGET_UNIX + return strdup (str); +#else + return _strdup (str); +#endif +} + +static +inline +ep_char8_t * +ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd) +{ + ptrdiff_t byte_len = strEnd - str; + ep_char8_t *buffer = reinterpret_cast(malloc(byte_len + 1)); + if (buffer != NULL) + { + memcpy (buffer, str, byte_len); + buffer [byte_len] = '\0'; + } + return buffer; +} + +static +inline +ep_char8_t * +ep_rt_utf8_string_strtok ( + ep_char8_t *str, + const ep_char8_t *delimiter, + ep_char8_t **context) +{ + STATIC_CONTRACT_NOTHROW; +#ifdef TARGET_UNIX + return strtok_r (str, delimiter, context); +#else + return strtok_s (str, delimiter, context); +#endif +} + +// STATIC_CONTRACT_NOTHROW +#undef ep_rt_utf8_string_snprintf +#define ep_rt_utf8_string_snprintf( \ + str, \ + str_len, \ + format, ...) \ +sprintf_s (reinterpret_cast(str), static_cast(str_len), reinterpret_cast(format), __VA_ARGS__) + +static +inline +bool +ep_rt_utf8_string_replace ( + ep_char8_t **str, + const ep_char8_t *strSearch, + const ep_char8_t *strReplacement +) +{ + STATIC_CONTRACT_NOTHROW; + if ((*str) == NULL) + return false; + + ep_char8_t* strFound = strstr(*str, strSearch); + if (strFound != NULL) + { + size_t strSearchLen = strlen(strSearch); + size_t newStrSize = strlen(*str) + strlen(strReplacement) - strSearchLen + 1; + ep_char8_t *newStr = reinterpret_cast(malloc(newStrSize)); + if (newStr == NULL) + { + *str = NULL; + return false; + } + ep_rt_utf8_string_snprintf(newStr, newStrSize, "%.*s%s%s", (int)(strFound - (*str)), *str, strReplacement, strFound + strSearchLen); + ep_rt_utf8_string_free(*str); + *str = newStr; + return true; + } + return false; +} + +static +ep_char16_t * +ep_rt_utf8_to_utf16le_string ( + const ep_char8_t *str, + size_t len) +{ + STATIC_CONTRACT_NOTHROW; + + if (!str) + return NULL; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implementation would just use strlen and malloc to make a new buffer, and would then copy the string chars one by one + size_t len_utf8 = strlen(str); + if (len_utf8 == 0) + return NULL; + + ep_char16_t *str_utf16 = reinterpret_cast(malloc ((len_utf8 + 1) * sizeof (ep_char16_t))); + if (!str_utf16) + return NULL; + + for (size_t i = 0; i < len_utf8; i++) + { + str_utf16[i] = str[i]; + } + + str_utf16[len_utf8] = 0; + return str_utf16; +} + +static +inline +ep_char16_t * +ep_rt_utf16_string_dup (const ep_char16_t *str) +{ + STATIC_CONTRACT_NOTHROW; + + if (!str) + return NULL; + + size_t str_size = (ep_rt_utf16_string_len (str) + 1) * sizeof (ep_char16_t); + ep_char16_t *str_dup = reinterpret_cast(malloc (str_size)); + if (str_dup) + memcpy (str_dup, str, str_size); + return str_dup; +} + +static +inline +void +ep_rt_utf8_string_free (ep_char8_t *str) +{ + STATIC_CONTRACT_NOTHROW; + + if (str) + free (str); +} + +static +inline +size_t +ep_rt_utf16_string_len (const ep_char16_t *str) +{ + STATIC_CONTRACT_NOTHROW; + extern size_t + ep_rt_aot_utf16_string_len (const ep_char16_t *str); + return ep_rt_aot_utf16_string_len(str); +} + +static +ep_char8_t * +ep_rt_utf16_to_utf8_string ( + const ep_char16_t *str, + size_t len) +{ + STATIC_CONTRACT_NOTHROW; + + if (!str) + return NULL; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Temp implementation that is the reverse of ep_rt_utf8_to_utf16le_string + size_t len_utf16 = len; + if(len_utf16 == -1) + { + len_utf16 = ep_rt_utf16_string_len (str); + } + + ep_char8_t *str_utf8 = reinterpret_cast(malloc ((len_utf16 + 1) * sizeof (ep_char8_t))); + if (!str_utf8) + return NULL; + + for (size_t i = 0; i < len_utf16; i++) + { + str_utf8[i] = (char)str[i]; + } + + str_utf8[len_utf16] = 0; + return str_utf8; +} + +static +inline +ep_char8_t * +ep_rt_utf16le_to_utf8_string ( + const ep_char16_t *str, + size_t len) +{ + return ep_rt_utf16_to_utf8_string (str, len); +} + +static +inline +void +ep_rt_utf16_string_free (ep_char16_t *str) +{ + STATIC_CONTRACT_NOTHROW; + + if (str) + free (str); +} + +static +inline +const ep_char8_t * +ep_rt_managed_command_line_get (void) +{ + STATIC_CONTRACT_NOTHROW; + //EP_UNREACHABLE ("Can not reach here"); + + return NULL; +} + +static +const ep_char8_t * +ep_rt_diagnostics_command_line_get (void) +{ + + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: revisit commandline for AOT + // return reinterpret_cast(::GetCommandLineA()); + + extern ep_char8_t *volatile _ep_rt_aot_diagnostics_cmd_line; + ep_char8_t *old_cmd_line = _ep_rt_aot_diagnostics_cmd_line; + return _ep_rt_aot_diagnostics_cmd_line; +} + +/* + * Thread. + */ + +static +inline +EventPipeThreadHolder * +thread_holder_alloc_func (void) +{ + STATIC_CONTRACT_NOTHROW; + EventPipeThreadHolder *instance = ep_thread_holder_alloc (ep_thread_alloc()); + if (instance) + ep_thread_register (ep_thread_holder_get_thread (instance)); + return instance; +} + +static +inline +void +thread_holder_free_func (EventPipeThreadHolder * thread_holder) +{ + STATIC_CONTRACT_NOTHROW; + if (thread_holder) { + ep_thread_unregister (ep_thread_holder_get_thread (thread_holder)); + ep_thread_holder_free (thread_holder); + } +} + +class EventPipeAotThreadHolderTLS { +public: + EventPipeAotThreadHolderTLS () + { + STATIC_CONTRACT_NOTHROW; + } + + ~EventPipeAotThreadHolderTLS () + { + STATIC_CONTRACT_NOTHROW; + + if (m_threadHolder) { + thread_holder_free_func (m_threadHolder); + m_threadHolder = NULL; + } + } + + static inline EventPipeThreadHolder * getThreadHolder () + { + STATIC_CONTRACT_NOTHROW; + return g_threadHolderTLS.m_threadHolder; + } + + static inline EventPipeThreadHolder * createThreadHolder () + { + STATIC_CONTRACT_NOTHROW; + + if (g_threadHolderTLS.m_threadHolder) { + thread_holder_free_func (g_threadHolderTLS.m_threadHolder); + g_threadHolderTLS.m_threadHolder = NULL; + } + g_threadHolderTLS.m_threadHolder = thread_holder_alloc_func (); + return g_threadHolderTLS.m_threadHolder; + } + +private: + EventPipeThreadHolder *m_threadHolder; + static thread_local EventPipeAotThreadHolderTLS g_threadHolderTLS; +}; + +static +void +ep_rt_thread_setup (void) +{ + STATIC_CONTRACT_NOTHROW; + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // Thread* thread_handle = SetupThreadNoThrow (); + // EP_ASSERT (thread_handle != NULL); +} + +static +inline +EventPipeThread * +ep_rt_thread_get (void) +{ + STATIC_CONTRACT_NOTHROW; + + EventPipeThreadHolder *thread_holder = EventPipeAotThreadHolderTLS::getThreadHolder (); + return thread_holder ? ep_thread_holder_get_thread (thread_holder) : NULL; +} + +static +inline +EventPipeThread * +ep_rt_thread_get_or_create (void) +{ + STATIC_CONTRACT_NOTHROW; + + EventPipeThreadHolder *thread_holder = EventPipeAotThreadHolderTLS::getThreadHolder (); + if (!thread_holder) + thread_holder = EventPipeAotThreadHolderTLS::createThreadHolder (); + + return ep_thread_holder_get_thread (thread_holder); +} + +static +inline +ep_rt_thread_handle_t +ep_rt_thread_get_handle (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // return GetThreadNULLOk (); + return NULL; +} + +static +inline +ep_rt_thread_id_t +ep_rt_thread_get_id (ep_rt_thread_handle_t thread_handle) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (thread_handle != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // return ep_rt_uint64_t_to_thread_id_t (thread_handle->GetOSThreadId64 ()); + // PalDebugBreak(); + return 0; +} + +static +inline +uint64_t +ep_rt_thread_id_t_to_uint64_t (ep_rt_thread_id_t thread_id) +{ + return static_cast(thread_id); +} + +static +inline +ep_rt_thread_id_t +ep_rt_uint64_t_to_thread_id_t (uint64_t thread_id) +{ + return static_cast(thread_id); +} + +static +inline +bool +ep_rt_thread_has_started (ep_rt_thread_handle_t thread_handle) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // return thread_handle != NULL && thread_handle->HasStarted (); + return true; +} + +static +inline +ep_rt_thread_activity_id_handle_t +ep_rt_thread_get_activity_id_handle (void) +{ + STATIC_CONTRACT_NOTHROW; + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // return GetThread (); + // PalDebugBreak(); + return NULL; +} + +static +inline +const uint8_t * +ep_rt_thread_get_activity_id_cref (ep_rt_thread_activity_id_handle_t activity_id_handle) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (activity_id_handle != NULL); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // return reinterpret_cast(activity_id_handle->GetActivityId ()); + // PalDebugBreak(); + return NULL; +} + +static +inline +void +ep_rt_thread_get_activity_id ( + ep_rt_thread_activity_id_handle_t activity_id_handle, + uint8_t *activity_id, + uint32_t activity_id_len) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (activity_id_handle != NULL); + EP_ASSERT (activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + + memcpy (activity_id, ep_rt_thread_get_activity_id_cref (activity_id_handle), EP_ACTIVITY_ID_SIZE); +} + +static +inline +void +ep_rt_thread_set_activity_id ( + ep_rt_thread_activity_id_handle_t activity_id_handle, + const uint8_t *activity_id, + uint32_t activity_id_len) +{ + STATIC_CONTRACT_NOTHROW; + EP_ASSERT (activity_id_handle != NULL); + EP_ASSERT (activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + + // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase + // TODO: Implement thread creation/management if needed + // activity_id_handle->SetActivityId (reinterpret_cast(activity_id)); + // PalDebugBreak(); +} + +#undef EP_YIELD_WHILE +#define EP_YIELD_WHILE(condition) {}//YIELD_WHILE(condition) + +/* + * ThreadSequenceNumberMap. + */ + +EP_RT_DEFINE_HASH_MAP_REMOVE(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, EventPipeThreadSessionState *, uint32_t) +EP_RT_DEFINE_HASH_MAP_ITERATOR(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, ep_rt_thread_sequence_number_hash_map_iterator_t, EventPipeThreadSessionState *, uint32_t) + +/* + * Volatile. + */ + +static +inline +uint32_t +ep_rt_volatile_load_uint32_t (const volatile uint32_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern uint32_t + ep_rt_aot_volatile_load_uint32_t (const volatile uint32_t *ptr); + return ep_rt_aot_volatile_load_uint32_t(ptr); +} + +static +inline +uint32_t +ep_rt_volatile_load_uint32_t_without_barrier (const volatile uint32_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern uint32_t + ep_rt_aot_volatile_load_uint32_t_without_barrier (const volatile uint32_t *ptr); + + return ep_rt_aot_volatile_load_uint32_t_without_barrier(ptr); +} + +static +inline +void +ep_rt_volatile_store_uint32_t ( + volatile uint32_t *ptr, + uint32_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_uint32_t ( + volatile uint32_t *ptr, + uint32_t value); + + ep_rt_aot_volatile_store_uint32_t(ptr, value); +} + +static +inline +void +ep_rt_volatile_store_uint32_t_without_barrier ( + volatile uint32_t *ptr, + uint32_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_uint32_t_without_barrier ( + volatile uint32_t *ptr, + uint32_t value); + + ep_rt_aot_volatile_store_uint32_t_without_barrier(ptr, value); +} + +static +inline +uint64_t +ep_rt_volatile_load_uint64_t (const volatile uint64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern uint64_t + ep_rt_aot_volatile_load_uint64_t (const volatile uint64_t *ptr); + + return ep_rt_aot_volatile_load_uint64_t(ptr); +} + +static +inline +uint64_t +ep_rt_volatile_load_uint64_t_without_barrier (const volatile uint64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern uint64_t + ep_rt_aot_volatile_load_uint64_t_without_barrier (const volatile uint64_t *ptr); + + return ep_rt_aot_volatile_load_uint64_t_without_barrier(ptr); +} + +static +inline +void +ep_rt_volatile_store_uint64_t ( + volatile uint64_t *ptr, + uint64_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_uint64_t ( + volatile uint64_t *ptr, + uint64_t value); + + ep_rt_aot_volatile_store_uint64_t(ptr, value); +} + +static +inline +void +ep_rt_volatile_store_uint64_t_without_barrier ( + volatile uint64_t *ptr, + uint64_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_uint64_t_without_barrier ( + volatile uint64_t *ptr, + uint64_t value); + ep_rt_aot_volatile_store_uint64_t_without_barrier(ptr, value); +} + +static +inline +int64_t +ep_rt_volatile_load_int64_t (const volatile int64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern int64_t + ep_rt_aot_volatile_load_int64_t (const volatile int64_t *ptr); + return ep_rt_aot_volatile_load_int64_t(ptr); +} + +static +inline +int64_t +ep_rt_volatile_load_int64_t_without_barrier (const volatile int64_t *ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern int64_t + ep_rt_aot_volatile_load_int64_t_without_barrier (const volatile int64_t *ptr); + return ep_rt_aot_volatile_load_int64_t_without_barrier(ptr); +} + +static +inline +void +ep_rt_volatile_store_int64_t ( + volatile int64_t *ptr, + int64_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_int64_t ( + volatile int64_t *ptr, + int64_t value); + ep_rt_aot_volatile_store_int64_t(ptr, value); +} + +static +inline +void +ep_rt_volatile_store_int64_t_without_barrier ( + volatile int64_t *ptr, + int64_t value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_int64_t_without_barrier ( + volatile int64_t *ptr, + int64_t value); + ep_rt_aot_volatile_store_int64_t_without_barrier(ptr, value); +} + +static +inline +void * +ep_rt_volatile_load_ptr (volatile void **ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern void * + ep_rt_aot_volatile_load_ptr (volatile void **ptr); + return ep_rt_aot_volatile_load_ptr(ptr); +} + +static +inline +void * +ep_rt_volatile_load_ptr_without_barrier (volatile void **ptr) +{ + STATIC_CONTRACT_NOTHROW; + extern void * + ep_rt_aot_volatile_load_ptr_without_barrier (volatile void **ptr); + return ep_rt_aot_volatile_load_ptr_without_barrier(ptr); +} + +static +inline +void +ep_rt_volatile_store_ptr ( + volatile void **ptr, + void *value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_ptr ( + volatile void **ptr, + void *value); + ep_rt_aot_volatile_store_ptr(ptr, value); +} + +static +inline +void +ep_rt_volatile_store_ptr_without_barrier ( + volatile void **ptr, + void *value) +{ + STATIC_CONTRACT_NOTHROW; + extern void + ep_rt_aot_volatile_store_ptr_without_barrier ( + volatile void **ptr, + void *value); + ep_rt_aot_volatile_store_ptr_without_barrier(ptr, value); +} + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_RT_AOT_H__ */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-config-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-config-aot.h new file mode 100644 index 0000000000000..d42cad689d5e5 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-config-aot.h @@ -0,0 +1,4 @@ +#ifndef __EVENTPIPE_RT_CONFIG_AOT_H__ +#define __EVENTPIPE_RT_CONFIG_AOT_H__ + +#endif /* __EVENTPIPE_RT_CONFIG_AOT_H__ */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-types-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-types-aot.h new file mode 100644 index 0000000000000..9aa547e6b4f4c --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-types-aot.h @@ -0,0 +1,347 @@ +// Implementation of ep-rt-types.h targeting AOT runtime. +#ifndef __EVENTPIPE_RT_TYPES_AOT_H__ +#define __EVENTPIPE_RT_TYPES_AOT_H__ + +#include + +#include + +#ifdef ENABLE_PERFTRACING + +#include "EmptyContainers.h" + +#ifdef TARGET_UNIX +#define __stdcall +#endif + +#ifdef DEBUG +#define EP_CHECKED_BUILD +#endif + +#undef EP_ASSERT +#ifdef EP_CHECKED_BUILD +#define EP_ASSERT(expr) _ASSERTE(expr) +#else +#define EP_ASSERT(expr) +#endif + +#undef EP_UNREACHABLE +#define EP_UNREACHABLE(msg) do { UNREACHABLE_MSG(msg); } while (0) + +#undef EP_LIKELY +#define EP_LIKELY(expr) expr + +#undef EP_UNLIKELY +#define EP_UNLIKELY(expr) expr + +template +struct _rt_aot_list_internal_t { + typedef struct SListElem_EP element_type_t; + typedef class SList_EP list_type_t; + list_type_t *list; +}; + +template +struct _rt_aot_queue_internal_t { + typedef struct SListElem_EP element_type_t; + typedef class SList_EP queue_type_t; + queue_type_t *queue; +}; + +template +struct _rt_aot_array_internal_t { + typedef T element_type_t; + typedef class CQuickArrayList_EP array_type_t; + array_type_t *array; +}; + +template +struct _rt_aot_array_iterator_internal_t { + typedef typename _rt_aot_array_internal_t::array_type_t array_iterator_type; + array_iterator_type *array; + size_t index; +}; + +typedef struct _rt_aot_table_callbacks_t { + void (*key_free_func)(void *); + void (*value_free_func)(void *); +} rt_aot_table_callbacks_t; + +template +struct _rt_aot_table_default_internal_t { + typedef class SHash_EP > > table_type_t; + rt_aot_table_callbacks_t callbacks; + table_type_t *table; +}; + +template +struct _rt_aot_table_remove_internal_t { + typedef class SHash_EP< MapSHashTraits_EP > table_type_t; + rt_aot_table_callbacks_t callbacks; + table_type_t *table; +}; + +class EventPipeAotStackHashTraits : public NoRemoveSHashTraits_EP< MapSHashTraits_EP > +{ +public: + typedef typename MapSHashTraits_EP::element_t element_t; + typedef typename MapSHashTraits_EP::count_t count_t; + + typedef StackHashKey * key_t; + + static key_t GetKey (element_t e) + { + extern StackHashKey * ep_stack_hash_entry_get_key (StackHashEntry *); + return ep_stack_hash_entry_get_key (e.Value ()); + } + + static bool Equals (key_t k1, key_t k2) + { + extern bool ep_stack_hash_key_equal (const void *, const void *); + return ep_stack_hash_key_equal (k1, k2); + } + + static count_t Hash (key_t k) + { + extern uint32_t ep_stack_hash_key_hash (const void *); + return (count_t)ep_stack_hash_key_hash (k); + } + + static element_t Null () + { + return element_t (NULL, NULL); + } + + static bool IsNull (const element_t &e) + { + return (e.Key () == NULL|| e.Value () == NULL); + } +}; + +template +struct _rt_aot_table_custom_internal_t { + typedef class SHash_EP table_type_t; + rt_aot_table_callbacks_t callbacks; + table_type_t *table; +}; + +class CLREventStatic; +struct _rt_aot_event_internal_t { + CLREventStatic *event; +}; + +class CrstStatic; +struct _rt_aot_lock_internal_t { + CrstStatic *lock; +}; + +class SpinLock; +struct _rt_aot_spin_lock_internal_t { + SpinLock *lock; +}; + +/* + * EventPipeBuffer. + */ + +#undef ep_rt_buffer_array_t +typedef struct _rt_aot_array_internal_t ep_rt_buffer_array_t; + +#undef ep_rt_buffer_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_buffer_array_iterator_t; + +/* + * EventPipeBufferList. + */ + +#undef ep_rt_buffer_list_array_t +typedef struct _rt_aot_array_internal_t ep_rt_buffer_list_array_t; + +#undef ep_rt_buffer_list_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_buffer_list_array_iterator_t; + +/* + * EventPipeEvent. + */ + +#undef ep_rt_event_list_t +typedef struct _rt_aot_list_internal_t ep_rt_event_list_t; + +#undef ep_rt_event_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_event_list_iterator_t; + +/* + * EventPipeFile. + */ + +#undef ep_rt_metadata_labels_hash_map_t +typedef struct _rt_aot_table_remove_internal_t ep_rt_metadata_labels_hash_map_t; + +#undef ep_rt_metadata_labels_hash_map_iterator_t +typedef class _rt_aot_table_remove_internal_t::table_type_t::Iterator ep_rt_metadata_labels_hash_map_iterator_t; + +#undef ep_rt_stack_hash_map_t +typedef struct _rt_aot_table_custom_internal_t ep_rt_stack_hash_map_t; + +#undef ep_rt_stack_hash_map_iterator_t +typedef class _rt_aot_table_custom_internal_t::table_type_t::Iterator ep_rt_stack_hash_map_iterator_t; + +/* + * EventPipeProvider. + */ + +#undef ep_rt_provider_list_t +typedef struct _rt_aot_list_internal_t ep_rt_provider_list_t; + +#undef ep_rt_provider_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_provider_list_iterator_t; + +#undef ep_rt_provider_callback_data_queue_t +typedef struct _rt_aot_queue_internal_t ep_rt_provider_callback_data_queue_t; + +/* + * EventPipeProviderConfiguration. + */ + +#undef ep_rt_provider_config_array_t +typedef struct _rt_aot_array_internal_t ep_rt_provider_config_array_t; + +#undef ep_rt_provider_config_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_provider_config_array_iterator_t; + +/* + * EventPipeSessionProvider. + */ + +#undef ep_rt_session_provider_list_t +typedef struct _rt_aot_list_internal_t ep_rt_session_provider_list_t; + +#undef ep_rt_session_provider_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_session_provider_list_iterator_t; + +/* + * EventPipeSequencePoint. + */ + +#undef ep_rt_sequence_point_list_t +typedef struct _rt_aot_list_internal_t ep_rt_sequence_point_list_t; + +#undef ep_rt_sequence_point_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_sequence_point_list_iterator_t; + +/* + * EventPipeThread. + */ + +#undef ep_rt_thread_list_t +typedef struct _rt_aot_list_internal_t ep_rt_thread_list_t; + +#undef ep_rt_thread_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_thread_list_iterator_t; + +#undef ep_rt_thread_array_t +typedef struct _rt_aot_array_internal_t ep_rt_thread_array_t; + +#undef ep_rt_thread_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_thread_array_iterator_t; + +/* + * EventPipeThreadSessionState. + */ + +#undef ep_rt_thread_session_state_list_t +typedef struct _rt_aot_list_internal_t ep_rt_thread_session_state_list_t; + +#undef ep_rt_thread_session_state_list_iterator_t +typedef class _rt_aot_list_internal_t::list_type_t::Iterator ep_rt_thread_session_state_list_iterator_t; + +#undef ep_rt_thread_session_state_array_t +typedef struct _rt_aot_array_internal_t ep_rt_thread_session_state_array_t; + +#undef ep_rt_thread_session_state_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_thread_session_state_array_iterator_t; + +/* + * EventPipe. + */ + +#undef ep_rt_session_id_array_t +typedef struct _rt_aot_array_internal_t ep_rt_session_id_array_t; + +#undef ep_rt_session_id_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_session_id_array_iterator_t; + +#undef ep_rt_method_desc_t +typedef class MethodDesc ep_rt_method_desc_t; + +#undef ep_rt_execution_checkpoint_array_t +typedef struct _rt_aot_array_internal_t ep_rt_execution_checkpoint_array_t; + +#undef ep_rt_execution_checkpoint_array_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_execution_checkpoint_array_iterator_t; + +/* + * PAL. + */ + +#undef ep_rt_env_array_utf16_t +typedef struct _rt_aot_array_internal_t ep_rt_env_array_utf16_t; + +#undef ep_rt_env_array_utf16_iterator_t +typedef struct _rt_aot_array_iterator_internal_t ep_rt_env_array_utf16_iterator_t; + +#undef ep_rt_file_handle_t +typedef class CFileStream * ep_rt_file_handle_t; + +#undef ep_rt_wait_event_handle_t +typedef struct _rt_aot_event_internal_t ep_rt_wait_event_handle_t; + +#undef ep_rt_lock_handle_t +typedef struct _rt_aot_lock_internal_t ep_rt_lock_handle_t; + +#undef ep_rt_spin_lock_handle_t +typedef _rt_aot_spin_lock_internal_t ep_rt_spin_lock_handle_t; + +/* + * Thread. + */ + +#undef ep_rt_thread_handle_t +typedef class Thread * ep_rt_thread_handle_t; + +#undef ep_rt_thread_activity_id_handle_t +typedef class Thread * ep_rt_thread_activity_id_handle_t; + +#undef ep_rt_thread_id_t +// #ifndef TARGET_UNIX +// typedef DWORD ep_rt_thread_id_t; +// #else +typedef size_t ep_rt_thread_id_t; +//#endif + +#undef ep_rt_thread_start_func +typedef size_t (__stdcall *ep_rt_thread_start_func)(void *lpThreadParameter); + +#undef ep_rt_thread_start_func_return_t +typedef size_t ep_rt_thread_start_func_return_t; + +#undef ep_rt_thread_params_t +typedef struct _rt_aot_thread_params_t { + ep_rt_thread_handle_t thread; + EventPipeThreadType thread_type; + ep_rt_thread_start_func thread_func; + void *thread_params; +} ep_rt_thread_params_t; + +/* + * ThreadSequenceNumberMap. + */ + +#undef ep_rt_thread_sequence_number_hash_map_t +typedef struct _rt_aot_table_remove_internal_t ep_rt_thread_sequence_number_hash_map_t; + +#undef ep_rt_thread_sequence_number_hash_map_iterator_t +typedef class _rt_aot_table_remove_internal_t::table_type_t::Iterator ep_rt_thread_sequence_number_hash_map_iterator_t; + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_RT_TYPES_AOT_H__ */ diff --git a/src/coreclr/nativeaot/Runtime/eventpipeadapter.h b/src/coreclr/nativeaot/Runtime/eventpipeadapter.h new file mode 100644 index 0000000000000..4156cbf1e4680 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipeadapter.h @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __EVENTPIPE_ADAPTER_H__ +#define __EVENTPIPE_ADAPTER_H__ + +#if defined(FEATURE_PERFTRACING) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gcenv.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "holder.h" +#include "SpinLock.h" + +class EventPipeAdapter final +{ +public: + static inline void Initialize() + { + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + ep_init(); + } + + static inline EventPipeProvider * CreateProvider(LPCWSTR providerName, EventPipeCallback callback, void* pCallbackContext) + { + ep_char8_t *providerNameUTF8 = ep_rt_utf16_to_utf8_string(reinterpret_cast(providerName), -1); + EventPipeProvider * provider = ep_create_provider (providerNameUTF8, callback, pCallbackContext); + ep_rt_utf8_string_free (providerNameUTF8); + return provider; + } + + static inline void DeleteProvider (EventPipeProvider * provider) + { + ep_delete_provider (provider); + } + + + static inline void FinishInitialize() + { + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + ep_finish_init(); + } + + static inline void Shutdown() + { + ep_shutdown(); + } + + static inline bool Enabled() + { + STATIC_CONTRACT_NOTHROW; + return ep_enabled(); + } + + static inline void Disable(EventPipeSessionID id) + { + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + ep_disable(id); + } + + static inline EventPipeProvider * GetProvider (LPCWSTR providerName) + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!providerName) + return NULL; + + ep_char8_t *providerNameUTF8 = ep_rt_utf16_to_utf8_string(reinterpret_cast(providerName), -1); + EventPipeProvider * provider = ep_get_provider (providerNameUTF8); + ep_rt_utf8_string_free(providerNameUTF8); + return provider; + } + + static inline EventPipeEvent * AddEvent( + EventPipeProvider *provider, + uint32_t eventID, + int64_t keywords, + uint32_t eventVersion, + EventPipeEventLevel level, + bool needStack, + uint8_t *metadata = NULL, + uint32_t metadataLen = 0) + { + return ep_provider_add_event(provider, eventID, keywords, eventVersion, level, needStack, metadata, metadataLen); + } + + static inline void WriteEvent( + EventPipeEvent *ep_event, + uint8_t *data, + uint32_t dataLen, + const GUID * activityId, + const GUID * relatedActivityId) + { + ep_write_event( + ep_event, + data, + dataLen, + reinterpret_cast(activityId), + reinterpret_cast(relatedActivityId)); + } + + static inline void WriteEvent( + EventPipeEvent *ep_event, + EventData *data, + uint32_t dataLen, + const GUID * activityId, + const GUID * relatedActivityId) + { + ep_write_event_2( + ep_event, + data, + dataLen, + reinterpret_cast(activityId), + reinterpret_cast(relatedActivityId)); + } +}; + +#endif // FEATURE_PERFTRACING +#endif // __EVENTPIPE_ADAPTER_H__ diff --git a/src/coreclr/nativeaot/Runtime/eventpipeadaptertypes.h b/src/coreclr/nativeaot/Runtime/eventpipeadaptertypes.h new file mode 100644 index 0000000000000..f473bde10488d --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipeadaptertypes.h @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __EVENTPIPE_ADAPTER_TYPES_H__ +#define __EVENTPIPE_ADAPTER_TYPES_H__ + +#if defined(FEATURE_PERFTRACING) + +typedef struct _EventFilterDescriptor EventFilterDescriptor; +typedef struct _EventPipeBufferList EventPipeBufferList; +typedef struct _EventPipeProvider EventPipeProvider; +typedef struct _EventPipeSession EventPipeSession; + +#endif // FEATURE_PERFTRACING +#endif // __EVENTPIPE_ADAPTER_TYPES_H__ diff --git a/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp new file mode 100644 index 0000000000000..3615daaeeb249 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "common.h" +#include "eventpipeadapter.h" + +#include "gcenv.h" +#include "regdisplay.h" +#include "StackFrameIterator.h" +#include "thread.h" +#include "SpinLock.h" + +#ifdef FEATURE_PERFTRACING + +struct EventPipeEventInstanceData +{ + void *ProviderID; + unsigned int EventID; + unsigned int ThreadID; + LARGE_INTEGER TimeStamp; + GUID ActivityId; + GUID RelatedActivityId; + const uint8_t *Payload; + unsigned int PayloadLength; +}; + +struct EventPipeSessionInfo +{ + FILETIME StartTimeAsUTCFileTime; + LARGE_INTEGER StartTimeStamp; + LARGE_INTEGER TimeStampFrequency; +}; + +EXTERN_C NATIVEAOT_API uint64_t __cdecl RhEventPipeInternal_Enable( + LPCWSTR outputFile, + EventPipeSerializationFormat format, + uint32_t circularBufferSizeInMB, + /* COR_PRF_EVENTPIPE_PROVIDER_CONFIG */ const void * pProviders, + uint32_t numProviders) +{ + PalDebugBreak(); + return 0; +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_Disable(uint64_t sessionID) +{ + EventPipeAdapter::Disable(sessionID); +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_CreateProvider( + LPCWSTR providerName, + EventPipeCallback pCallbackFunc, + void* pCallbackContext) +{ + EventPipeProvider* pProvider = EventPipeAdapter::CreateProvider(providerName, pCallbackFunc, pCallbackContext); + return reinterpret_cast(pProvider); +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_DefineEvent( + intptr_t provHandle, + uint32_t eventID, + int64_t keywords, + uint32_t eventVersion, + uint32_t level, + void *pMetadata, + uint32_t metadataLength) +{ + EventPipeEvent *pEvent = NULL; + + _ASSERTE(provHandle != 0); + EventPipeProvider *pProvider = reinterpret_cast(provHandle); + pEvent = EventPipeAdapter::AddEvent(pProvider, eventID, keywords, eventVersion, (EventPipeEventLevel)level, /* needStack = */ true, (uint8_t *)pMetadata, metadataLength); + _ASSERTE(pEvent != NULL); + + return reinterpret_cast(pEvent); +} + +EXTERN_C NATIVEAOT_API intptr_t __cdecl RhEventPipeInternal_GetProvider(LPCWSTR providerName) +{ + EventPipeProvider* pProvider = EventPipeAdapter::GetProvider(providerName); + return reinterpret_cast(pProvider); +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_DeleteProvider(intptr_t provHandle) +{ + if (provHandle != 0) + { + EventPipeProvider *pProvider = reinterpret_cast(provHandle); + EventPipeAdapter::DeleteProvider(pProvider); + } +} + +EXTERN_C NATIVEAOT_API int __cdecl RhEventPipeInternal_EventActivityIdControl(uint32_t controlCode, GUID *pActivityId) +{ + PalDebugBreak(); + return 0; +} + +EXTERN_C NATIVEAOT_API void __cdecl RhEventPipeInternal_WriteEventData( + intptr_t eventHandle, + EventData *pEventData, + uint32_t eventDataCount, + const GUID * pActivityId, + const GUID * pRelatedActivityId) +{ + _ASSERTE(eventHandle != 0); + EventPipeEvent *pEvent = reinterpret_cast(eventHandle); + EventPipeAdapter::WriteEvent(pEvent, pEventData, eventDataCount, pActivityId, pRelatedActivityId); +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_GetSessionInfo(uint64_t sessionID, EventPipeSessionInfo *pSessionInfo) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_GetNextEvent(uint64_t sessionID, EventPipeEventInstanceData *pInstance) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_SignalSession(uint64_t sessionID) +{ + PalDebugBreak(); + return FALSE; +} + +EXTERN_C NATIVEAOT_API UInt32_BOOL __cdecl RhEventPipeInternal_WaitForSessionSignal(uint64_t sessionID, int32_t timeoutMs) +{ + PalDebugBreak(); + return FALSE; +} + +#endif // FEATURE_PERFTRACING diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index 9acfb0b487cea..d1e240378e802 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -26,6 +26,10 @@ #include "RestrictedCallouts.h" #include "yieldprocessornormalized.h" +#ifdef FEATURE_PERFTRACING +#include "EventPipeInterface.h" +#endif + #ifndef DACCESS_COMPILE #ifdef PROFILE_STARTUP @@ -97,6 +101,14 @@ static bool InitDLL(HANDLE hPalInstance) return false; #endif +#ifdef FEATURE_PERFTRACING + // Initialize EventPipe + EventPipeAdapter_Initialize(); + // Initialize DS + DiagnosticServerAdapter_Initialize(); + DiagnosticServerAdapter_PauseForDiagnosticsMonitor(); +#endif + // // Initialize support for registering GC and HandleTable callouts. // @@ -141,6 +153,13 @@ static bool InitDLL(HANDLE hPalInstance) STARTUP_TIMELINE_EVENT(GC_INIT_COMPLETE); +#ifdef FEATURE_PERFTRACING + // Finish setting up rest of EventPipe - specifically enable SampleProfiler if it was requested at startup. + // SampleProfiler needs to cooperate with the GC which hasn't fully finished setting up in the first part of the + // EventPipe initialization, so this is done after the GC has been fully initialized. + EventPipeAdapter_FinishInitialize(); +#endif + #ifndef USE_PORTABLE_HELPERS if (!DetectCPUFeatures()) return false; @@ -459,6 +478,11 @@ static void __cdecl OnProcessExit() // or run managed code at shutdown, so we will not try detaching it. Thread* currentThread = ThreadStore::RawGetCurrentThread(); g_threadPerformingShutdown = currentThread; + +#ifdef FEATURE_PERFTRACING + EventPipeAdapter_Shutdown(); + DiagnosticServerAdapter_Shutdown(); +#endif } #endif diff --git a/src/coreclr/nativeaot/Runtime/thread.h b/src/coreclr/nativeaot/Runtime/thread.h index 698d88abab485..d42a78e922f20 100644 --- a/src/coreclr/nativeaot/Runtime/thread.h +++ b/src/coreclr/nativeaot/Runtime/thread.h @@ -331,10 +331,8 @@ typedef DacScanCallbackData EnumGcRefScanContext; typedef void EnumGcRefCallbackFunc(PTR_PTR_Object, EnumGcRefScanContext* callbackData, uint32_t flags); #else // DACCESS_COMPILE -#ifndef __GCENV_BASE_INCLUDED__ struct ScanContext; typedef void promote_func(PTR_PTR_Object, ScanContext*, unsigned); -#endif // !__GCENV_BASE_INCLUDED__ typedef promote_func EnumGcRefCallbackFunc; typedef ScanContext EnumGcRefScanContext; diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index 2893bc6289758..8921e7b019be6 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -632,6 +632,11 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCal #endif // HOST_WASM } +REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext) +{ + return PalStartBackgroundWork(callback, pCallbackContext, UInt32_FALSE); +} + // Returns a 64-bit tick count with a millisecond resolution. It tries its best // to return monotonically increasing counts and avoid being affected by changes // to the system clock (either due to drift or due to explicit changes to system diff --git a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp index 8e8b85356b28d..8ce4fbdecc2bb 100644 --- a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp @@ -612,6 +612,11 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartFinalizerThread(_In_ BackgroundCal return PalStartBackgroundWork(callback, pCallbackContext, TRUE); } +REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext) +{ + return PalStartBackgroundWork(callback, pCallbackContext, FALSE); +} + REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalEventEnabled(REGHANDLE regHandle, _In_ const EVENT_DESCRIPTOR* eventDescriptor) { return !!EventEnabled(regHandle, eventDescriptor); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 4739cacc3ec2a..e9a18dcf92a57 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -173,6 +173,7 @@ + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.NativeAot.cs new file mode 100644 index 0000000000000..1a29085096d67 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.NativeAot.cs @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime; +using System.Runtime.InteropServices; + +#if FEATURE_PERFTRACING + +namespace System.Diagnostics.Tracing +{ + // + // NOTE: + // + // The implementation below takes some manual marshaling actions to ensure arguments are in + // primitive form before they are passed through to the underlying RuntimeImports.Rh* + // function. + // + // These extra steps are necessary only if the RuntimeImports mechanism represents "raw" + // calls into the native runtime (as has been the case at least in the distant past). + // + // If the RuntimeImports mechanism automatically applies rich p/invoke marshaling to all of + // these calls, then all of the manual steps below are unnecessary and can be removed (by + // making the RuntimeImports.Rh* function signatures generally match the corresponding + // EventPipeInternal function signatures; in other words, by making the RuntimeImports.Rh* + // functions look like the QCalls in EventPipe.CoreCLR.cs). + // + internal static partial class EventPipeInternal + { + // + // These PInvokes are used by the configuration APIs to interact with EventPipe. + // + private static unsafe ulong Enable( + char* outputFile, + EventPipeSerializationFormat format, + uint circularBufferSizeInMB, + EventPipeProviderConfigurationNative* providers, + uint numProviders) + { + return RuntimeImports.RhEventPipeInternal_Enable( + outputFile, + (int)format, + circularBufferSizeInMB, + providers, + numProviders); + } + + internal static void Disable(ulong sessionID) + { + RuntimeImports.RhEventPipeInternal_Disable(sessionID); + } + + // + // These PInvokes are used by EventSource to interact with the EventPipe. + // + +// private static extern unsafe IntPtr CreateProvider(string providerName, IntPtr callbackFunc, IntPtr callbackContext); + + internal static unsafe IntPtr CreateProvider(string providerName, + delegate* unmanaged callbackFunc, + void* callbackContext) + => CreateProvider(providerName, (IntPtr)callbackFunc, (IntPtr)callbackContext); + //internal static unsafe IntPtr CreateProvider(string providerName, IntPtr callbackFunc, IntPtr callbackContext); + + internal static unsafe IntPtr CreateProvider(string providerName, IntPtr callbackFunc, IntPtr callbackContext) + { + fixed (char* pProviderName = providerName) + { + return RuntimeImports.RhEventPipeInternal_CreateProvider( + pProviderName, + callbackFunc, + callbackContext); + } + } + + internal static unsafe IntPtr DefineEvent( + IntPtr provHandle, + uint eventID, + long keywords, + uint eventVersion, + uint level, + void *pMetadata, + uint metadataLength) + { + return RuntimeImports.RhEventPipeInternal_DefineEvent( + provHandle, + eventID, + keywords, + eventVersion, + level, + pMetadata, + metadataLength); + } + + internal static unsafe IntPtr GetProvider(string providerName) + { + fixed (char* pProviderName = providerName) + { + return RuntimeImports.RhEventPipeInternal_GetProvider(pProviderName); + } + } + + internal static void DeleteProvider(IntPtr provHandle) + { + RuntimeImports.RhEventPipeInternal_DeleteProvider(provHandle); + } + + internal static unsafe int EventActivityIdControl(uint controlCode, ref Guid activityId) + { + // + // Ensure that the address passed to native code is never on the managed heap, while still + // managing the supplied byref in an in/out manner. + // + Guid localActivityId = activityId; + try { return RuntimeImports.RhEventPipeInternal_EventActivityIdControl(controlCode, &localActivityId); } + finally { activityId = localActivityId; } + } + + internal static unsafe void WriteEventData( + IntPtr eventHandle, + EventProvider.EventData* pEventData, + uint dataCount, + Guid* activityId, + Guid* relatedActivityId) + { + RuntimeImports.RhEventPipeInternal_WriteEventData( + eventHandle, + pEventData, + dataCount, + activityId, + relatedActivityId); + } + + // + // These PInvokes are used as part of the EventPipeEventDispatcher. + // + internal static unsafe bool GetSessionInfo(ulong sessionID, EventPipeSessionInfo* pSessionInfo) + { + uint rawBool = RuntimeImports.RhEventPipeInternal_GetSessionInfo(sessionID, pSessionInfo); + return (rawBool != 0); + } + + internal static unsafe bool GetNextEvent(ulong sessionID, EventPipeEventInstanceData* pInstance) + { + uint rawBool = RuntimeImports.RhEventPipeInternal_GetNextEvent(sessionID, pInstance); + return (rawBool != 0); + } + + internal static bool SignalSession(ulong sessionID) + { + uint rawBool = RuntimeImports.RhEventPipeInternal_SignalSession(sessionID); + return (rawBool != 0); + } + + internal static bool WaitForSessionSignal(ulong sessionID, int timeoutMs) + { + uint rawBool = RuntimeImports.RhEventPipeInternal_WaitForSessionSignal(sessionID, timeoutMs); + return (rawBool != 0); + } + } +} + +#endif // FEATURE_PERFTRACING + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 91894b1559e4b..bb203368d6dbb 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -691,6 +691,78 @@ public GCFrameRegistration(void* allocation, uint elemCount, bool areByRefs = tr [RuntimeImport(RuntimeLibrary, "RhpEtwExceptionThrown")] internal static extern unsafe void RhpEtwExceptionThrown(char* exceptionTypeName, char* exceptionMessage, IntPtr faultingIP, long hresult); +#if FEATURE_PERFTRACING + + // + // EventPipeInternal helpers. + // + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial ulong RhEventPipeInternal_Enable( + char* outputFile, + int format, + uint circularBufferSizeInMB, + void* providers, + uint numProviders); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static partial void RhEventPipeInternal_Disable(ulong sessionID); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial IntPtr RhEventPipeInternal_CreateProvider(char* providerName, IntPtr callbackFunc, IntPtr callbackContext); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial IntPtr RhEventPipeInternal_DefineEvent( + IntPtr provHandle, + uint eventID, + long keywords, + uint eventVersion, + uint level, + void *pMetadata, + uint metadataLength); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial IntPtr RhEventPipeInternal_GetProvider(char* providerName); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static partial void RhEventPipeInternal_DeleteProvider(IntPtr provHandle); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial int RhEventPipeInternal_EventActivityIdControl(uint controlCode, Guid* activityId); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial void RhEventPipeInternal_WriteEventData( + IntPtr eventHandle, + void* pEventData, + uint dataCount, + Guid* activityId, + Guid* relatedActivityId); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial uint RhEventPipeInternal_GetSessionInfo(ulong sessionID, void* pSessionInfo); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static unsafe partial uint RhEventPipeInternal_GetNextEvent(ulong sessionID, void* pInstance); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static partial uint RhEventPipeInternal_SignalSession(ulong sessionID); + + [LibraryImport(RuntimeLibrary)] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + internal static partial uint RhEventPipeInternal_WaitForSessionSignal(ulong sessionID, int timeoutMs); + +#endif // FEATURE_PERFTRACING + // // Interlocked helpers // diff --git a/src/coreclr/tools/aot/ILCompiler/reproNative/reproNative.vcxproj b/src/coreclr/tools/aot/ILCompiler/reproNative/reproNative.vcxproj index ee8d32964d805..26251393ffa3e 100644 --- a/src/coreclr/tools/aot/ILCompiler/reproNative/reproNative.vcxproj +++ b/src/coreclr/tools/aot/ILCompiler/reproNative/reproNative.vcxproj @@ -81,7 +81,7 @@ Console true - $(ArtifactsRoot)bin\repro\x64\Debug\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\System.IO.Compression.Native.Aot.lib + $(ArtifactsRoot)bin\repro\x64\Debug\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\System.IO.Compression.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Debug\aotsdk\eventpipe-disabled.lib @@ -101,7 +101,7 @@ true true true - $(ArtifactsRoot)bin\repro\x64\Checked\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\System.IO.Compression.Native.Aot.lib + $(ArtifactsRoot)bin\repro\x64\Checked\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\System.IO.Compression.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Checked\aotsdk\eventpipe-disabled.lib @@ -121,7 +121,7 @@ true true true - $(ArtifactsRoot)bin\repro\x64\Release\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\System.IO.Compression.Native.Aot.lib + $(ArtifactsRoot)bin\repro\x64\Release\repro.obj;$(Win32SDKLibs);%(AdditionalDependencies);$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\Runtime.WorkstationGC.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\System.Globalization.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\System.IO.Compression.Native.Aot.lib;$(ArtifactsRoot)bin\coreclr\windows.x64.Release\aotsdk\eventpipe-disabled.lib diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj index cc24d8f4a83ea..22abed2826235 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj @@ -4,6 +4,7 @@ $(NetCoreAppCurrent);$(NetFrameworkMinimum) true true + true diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj index 8001203352b58..411f12fb69124 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/NativeAotTests/System.Diagnostics.DiagnosticSource.NativeAotTests.proj @@ -1,7 +1,12 @@ - + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index 758e26df888c2..5c01e52e0e467 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -35,6 +35,8 @@ public static class Keywords private IncrementingPollingCounter? _allocRateCounter; private PollingCounter? _timerCounter; private PollingCounter? _fragmentationCounter; + +#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase private PollingCounter? _committedCounter; private IncrementingPollingCounter? _exceptionCounter; private PollingCounter? _gcTimeCounter; @@ -44,6 +46,8 @@ public static class Keywords private PollingCounter? _lohSizeCounter; private PollingCounter? _pohSizeCounter; private PollingCounter? _assemblyCounter; +#endif // !NATIVEAOT + private PollingCounter? _ilBytesJittedCounter; private PollingCounter? _methodsJittedCounter; private IncrementingPollingCounter? _jitTimeCounter; @@ -103,6 +107,8 @@ protected override void OnEventCommand(EventCommandEventArgs command) var gcInfo = GC.GetGCMemoryInfo(); return gcInfo.HeapSizeBytes != 0 ? gcInfo.FragmentedBytes * 100d / gcInfo.HeapSizeBytes : 0; }) { DisplayName = "GC Fragmentation", DisplayUnits = "%" }; + +#if !NATIVEAOT // TODO _committedCounter ??= new PollingCounter("gc-committed", this, () => ((double)GC.GetGCMemoryInfo().TotalCommittedBytes / 1_000_000)) { DisplayName = "GC Committed Bytes", DisplayUnits = "MB" }; _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; @@ -112,6 +118,8 @@ protected override void OnEventCommand(EventCommandEventArgs command) _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; _pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" }; _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; +#endif // !NATIVEAOT + _ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.JitInfo.GetCompiledILBytes()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" }; _methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.JitInfo.GetCompiledMethodCount()) { DisplayName = "Number of Methods Jitted" }; _jitTimeCounter ??= new IncrementingPollingCounter("time-in-jit", this, () => System.Runtime.JitInfo.GetCompilationTime().TotalMilliseconds) { DisplayName = "Time spent in JIT", DisplayUnits = "ms", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs index 29446e444073c..45f17feec6da0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs @@ -185,9 +185,11 @@ public static void Free(NativeOverlapped* nativeOverlappedPtr) #if FEATURE_PERFTRACING #if !((TARGET_BROWSER || TARGET_WASI) && !FEATURE_WASM_THREADS) +#if !NATIVEAOT // TODO shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase if (NativeRuntimeEventSource.Log.IsEnabled()) NativeRuntimeEventSource.Log.ThreadPoolIOPack(pNativeOverlapped); #endif +#endif #endif NativeOverlapped* pRet = pNativeOverlapped; diff --git a/src/native/eventpipe/ep-rt-config.h b/src/native/eventpipe/ep-rt-config.h index 4d5a6cc98c1c2..ea4475227339a 100644 --- a/src/native/eventpipe/ep-rt-config.h +++ b/src/native/eventpipe/ep-rt-config.h @@ -1,9 +1,9 @@ #ifndef __EVENTPIPE_RT_CONFIG_H__ #define __EVENTPIPE_RT_CONFIG_H__ -#include "ep-shared-config.h" +#include -#ifndef FEATURE_CORECLR +#if !defined(FEATURE_CORECLR) && !defined(FEATURE_NATIVEAOT) #include @@ -16,7 +16,7 @@ #define DS_RT_H #define DS_RT_TYPES_H -#else /* !FEATURE_CORECLR */ +#elif defined(FEATURE_CORECLR) #ifndef EP_NO_RT_DEPENDENCY #include "common.h" @@ -43,6 +43,31 @@ #define DS_RT_H "ds-rt-coreclr.h" #define DS_RT_TYPES_H "ds-rt-types-coreclr.h" +#elif defined(FEATURE_NATIVEAOT) + +#ifndef EP_NO_RT_DEPENDENCY +#include "common.h" +#endif + +#if defined(FEATURE_PERFTRACING) +#define ENABLE_PERFTRACING +#endif + +#ifdef TARGET_WINDOWS +#define HOST_WIN32 +#endif + +#if defined(FEATURE_PERFTRACING) && defined(FEATURE_PROFAPI_ATTACH_DETACH) && defined(DACCESS_COMPILE) +#undef FEATURE_PROFAPI_ATTACH_DETACH +#endif + +#define EP_RT_H +#define EP_RT_TYPES_H +#define EP_RT_CONFIG_H + +#define DS_RT_H +#define DS_RT_TYPES_H + #endif #ifndef EP_NO_RT_DEPENDENCY diff --git a/src/tests/tracing/eventpipe/common/IpcTraceTest.cs b/src/tests/tracing/eventpipe/common/IpcTraceTest.cs index 49e6e2774f8f4..17c0562675bc8 100644 --- a/src/tests/tracing/eventpipe/common/IpcTraceTest.cs +++ b/src/tests/tracing/eventpipe/common/IpcTraceTest.cs @@ -167,7 +167,7 @@ private int Fail(string message = "") return -1; } - private int Validate() + private int Validate(bool enableRundownProvider = true) { // FIXME: This is a bandaid fix for a deadlock in EventPipeEventSource caused by // the lazy caching in the Regex library. The caching creates a ConcurrentDictionary @@ -212,7 +212,7 @@ private int Validate() Logger.logger.Log("Connecting to EventPipe..."); try { - _eventPipeSession = client.StartEventPipeSession(_testProviders.Concat(_sentinelProviders)); + _eventPipeSession = client.StartEventPipeSession(_testProviders.Concat(_sentinelProviders), enableRundownProvider); } catch (DiagnosticsClientException ex) { @@ -392,13 +392,14 @@ public static int RunAndValidateEventCounts( Action eventGeneratingAction, List providers, int circularBufferMB=1024, - Func> optionalTraceValidator = null) + Func> optionalTraceValidator = null, + bool enableRundownProvider = true) { Logger.logger.Log("==TEST STARTING=="); var test = new IpcTraceTest(expectedEventCounts, eventGeneratingAction, providers, circularBufferMB, optionalTraceValidator); try { - var ret = test.Validate(); + var ret = test.Validate(enableRundownProvider); if (ret == 100) Logger.logger.Log("==TEST FINISHED: PASSED!=="); else diff --git a/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.cs b/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.cs new file mode 100644 index 0000000000000..b6577fc05bdac --- /dev/null +++ b/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics.Tracing; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using Microsoft.Diagnostics.Tracing; +using Tracing.Tests.Common; +using Microsoft.Diagnostics.NETCore.Client; + +namespace Tracing.Tests.SimpleProviderValidation +{ + public sealed class MyEventSource : EventSource + { + private MyEventSource() {} + public static MyEventSource Log = new MyEventSource(); + public void MyEvent() { WriteEvent(1, "MyEvent"); } + } + + public class ProviderValidation + { + public static int Main() + { + // This test validates that the rundown events are present + // and that providers turned on that generate events are being written to + // the stream. + + var providers = new List() + { + new EventPipeProvider("MyEventSource", EventLevel.Verbose), + new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", EventLevel.Verbose) + }; + + var ret = IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, providers, 1024, enableRundownProvider:false); + if (ret < 0) + return ret; + else + return 100; + } + + private static Dictionary _expectedEventCounts = new Dictionary() + { + { "MyEventSource", 1 }, + { "Microsoft-DotNETCore-EventPipe", 1} + }; + + private static Action _eventGeneratingAction = () => + { + Logger.logger.Log($"Firing an event..."); + MyEventSource.Log.MyEvent(); + }; + } +} diff --git a/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.csproj b/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.csproj new file mode 100644 index 0000000000000..34d588f3c2dd1 --- /dev/null +++ b/src/tests/tracing/eventpipe/simpleprovidervalidation/simpleprovidervalidation.csproj @@ -0,0 +1,17 @@ + + + .NETCoreApp + exe + true + true + true + true + true + true + + + + + + +