[NativeAOT] Handle event pipe environment variable configuration and output to file...
authorElinor Fung <elfung@microsoft.com>
Thu, 25 May 2023 19:40:52 +0000 (21:40 +0200)
committerGitHub <noreply@github.com>
Thu, 25 May 2023 19:40:52 +0000 (21:40 +0200)
Updates to NativeAOT event pipe:
- Respect environment variable configuration
- Handle writing out to a file
- Enable tracing/eventpipe/config/name_config_with_pid test, which uses environment variable configuration to write directly to a file.

14 files changed:
src/coreclr/gc/env/gcenv.structs.h
src/coreclr/nativeaot/Runtime/PalRedhawk.h
src/coreclr/nativeaot/Runtime/PalRedhawkFunctions.h
src/coreclr/nativeaot/Runtime/RhConfig.cpp
src/coreclr/nativeaot/Runtime/RhConfig.h
src/coreclr/nativeaot/Runtime/SpinLock.h
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-types-aot.h
src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp
src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp
src/tests/issues.targets
src/tests/tracing/eventpipe/config/name_config_with_pid.cs
src/tests/tracing/eventpipe/config/name_config_with_pid.csproj

index 0019ae6..9f287ec 100644 (file)
@@ -17,20 +17,6 @@ typedef void * HANDLE;
 
 #ifdef TARGET_UNIX
 
-typedef char TCHAR;
-#define _T(s) s
-
-#else
-
-#ifndef _INC_WINDOWS
-typedef wchar_t TCHAR;
-#define _T(s) L##s
-#endif
-
-#endif
-
-#ifdef TARGET_UNIX
-
 class EEThreadId
 {
     pthread_t m_id;
index 0b2d717..a718812 100644 (file)
@@ -17,8 +17,9 @@
 
 #include <sal.h>
 #include <stdarg.h>
-#include "gcenv.structs.h"
+#include "gcenv.structs.h" // CRITICAL_SECTION
 #include "IntrinsicConstants.h"
+#include "PalRedhawkCommon.h"
 
 #ifndef PAL_REDHAWK_INCLUDED
 #define PAL_REDHAWK_INCLUDED
@@ -50,7 +51,6 @@
 #endif // !_MSC_VER
 
 #ifndef _INC_WINDOWS
-//#ifndef DACCESS_COMPILE
 
 // There are some fairly primitive type definitions below but don't pull them into the rest of Redhawk unless
 // we have to (in which case these definitions will move to CommonTypes.h).
@@ -65,14 +65,13 @@ typedef void *              LPOVERLAPPED;
 
 #ifdef TARGET_UNIX
 #define __stdcall
+typedef char TCHAR;
+#define _T(s) s
+#else
+typedef wchar_t TCHAR;
+#define _T(s) L##s
 #endif
 
-#ifndef __GCENV_BASE_INCLUDED__
-#define CALLBACK            __stdcall
-#define WINAPI              __stdcall
-#define WINBASEAPI          __declspec(dllimport)
-#endif //!__GCENV_BASE_INCLUDED__
-
 #ifdef TARGET_UNIX
 #define DIRECTORY_SEPARATOR_CHAR '/'
 #else // TARGET_UNIX
@@ -101,9 +100,6 @@ typedef struct _GUID {
 
 #define DECLARE_HANDLE(_name) typedef HANDLE _name
 
-// defined in gcrhenv.cpp
-bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount);
-
 struct FILETIME
 {
     uint32_t dwLowDateTime;
@@ -502,7 +498,6 @@ typedef enum _EXCEPTION_DISPOSITION {
 #define NULL_AREA_SIZE                   (64*1024)
 #endif
 
-//#endif // !DACCESS_COMPILE
 #endif // !_INC_WINDOWS
 
 
@@ -510,10 +505,12 @@ typedef enum _EXCEPTION_DISPOSITION {
 #ifndef DACCESS_COMPILE
 #ifndef _INC_WINDOWS
 
-#ifndef __GCENV_BASE_INCLUDED__
+#ifndef TRUE
 #define TRUE                    1
+#endif
+#ifndef FALSE
 #define FALSE                   0
-#endif // !__GCENV_BASE_INCLUDED__
+#endif
 
 #define INVALID_HANDLE_VALUE    ((HANDLE)(intptr_t)-1)
 
@@ -750,6 +747,9 @@ REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalRegisterHijackCallback(_In_ PalH
 
 #ifdef FEATURE_ETW
 REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalEventEnabled(REGHANDLE regHandle, _In_ const EVENT_DESCRIPTOR* eventDescriptor);
+REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI PalEventRegister(const GUID * arg1, void * arg2, void * arg3, REGHANDLE * arg4);
+REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI PalEventUnregister(REGHANDLE arg1);
+REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t arg3, EVENT_DATA_DESCRIPTOR * arg4);
 #endif
 
 REDHAWK_PALIMPORT _Ret_maybenull_ void* REDHAWK_PALAPI PalSetWerDataBuffer(_In_ void* pNewBuffer);
@@ -776,6 +776,8 @@ REDHAWK_PALIMPORT uint64_t PalQueryPerformanceFrequency();
 
 REDHAWK_PALIMPORT void PalPrintFatalError(const char* message);
 
+REDHAWK_PALIMPORT char* PalCopyTCharAsChar(const TCHAR* toCopy);
+
 #ifdef TARGET_UNIX
 REDHAWK_PALIMPORT int32_t __cdecl _stricmp(const char *string1, const char *string2);
 #endif // TARGET_UNIX
index b03fc00..4c17659 100644 (file)
@@ -37,24 +37,6 @@ inline void PalEnterCriticalSection(CRITICAL_SECTION * arg1)
     EnterCriticalSection(arg1);
 }
 
-extern "C" uint32_t __stdcall EventRegister(const GUID *, void *, void *, REGHANDLE *);
-inline uint32_t PalEventRegister(const GUID * arg1, void * arg2, void * arg3, REGHANDLE * arg4)
-{
-    return EventRegister(arg1, arg2, arg3, arg4);
-}
-
-extern "C" uint32_t __stdcall EventUnregister(REGHANDLE);
-inline uint32_t PalEventUnregister(REGHANDLE arg1)
-{
-    return EventUnregister(arg1);
-}
-
-extern "C" uint32_t __stdcall EventWrite(REGHANDLE, const EVENT_DESCRIPTOR *, uint32_t, EVENT_DATA_DESCRIPTOR *);
-inline uint32_t PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t arg3, EVENT_DATA_DESCRIPTOR * arg4)
-{
-    return EventWrite(arg1, arg2, arg3, arg4);
-}
-
 extern "C" void __stdcall FlushProcessWriteBuffers();
 inline void PalFlushProcessWriteBuffers()
 {
index a321b37..928778b 100644 (file)
 
 #include <string.h>
 
-bool RhConfig::ReadConfigValue(_In_z_ const char *name, uint64_t* pValue, bool decimal)
+#define DOTNET_PREFIX _T("DOTNET_")
+#define DOTNET_PREFIX_LEN STRING_LENGTH(DOTNET_PREFIX)
+
+namespace
+{
+    void GetEnvironmentConfigName(const char* name, TCHAR* buffer, uint32_t bufferSize)
+    {
+        assert(DOTNET_PREFIX_LEN + strlen(name) < bufferSize);
+        memcpy(buffer, DOTNET_PREFIX, (DOTNET_PREFIX_LEN) * sizeof(TCHAR));
+    #ifdef TARGET_WINDOWS
+        size_t nameLen = strlen(name);
+        for (size_t i = 0; i < nameLen; i++)
+        {
+            buffer[DOTNET_PREFIX_LEN + i] = name[i];
+        }
+        buffer[DOTNET_PREFIX_LEN + nameLen] = '\0';
+    #else
+        strcpy(buffer + DOTNET_PREFIX_LEN, name);
+    #endif
+    }
+}
+
+bool RhConfig::Environment::TryGetBooleanValue(const char* name, bool* value)
+{
+    uint64_t intValue;
+    if (!TryGetIntegerValue(name, &intValue))
+        return false;
+
+    *value = intValue != 0;
+    return true;
+}
+
+bool RhConfig::Environment::TryGetIntegerValue(const char* name, uint64_t* value, bool decimal)
 {
+    TCHAR variableName[64];
+    GetEnvironmentConfigName(name, variableName, ARRAY_SIZE(variableName));
+
     TCHAR buffer[CONFIG_VAL_MAXLEN + 1]; // hex digits plus a nul terminator.
     const uint32_t cchBuffer = ARRAY_SIZE(buffer);
+    uint32_t cchResult = PalGetEnvironmentVariable(variableName, buffer, cchBuffer);
+    if (cchResult == 0 || cchResult >= cchBuffer)
+        return false;
 
-    uint32_t cchResult = 0;
-    TCHAR variableName[64] = _T("DOTNET_");
-    assert(ARRAY_SIZE("DOTNET_") - 1 + strlen(name) < ARRAY_SIZE(variableName));
-#ifdef TARGET_WINDOWS
-    for (size_t i = 0; i < strlen(name); i++)
+    // Environment variable was set. Convert it to an integer.
+    uint64_t uiResult = 0;
+    for (uint32_t i = 0; i < cchResult; i++)
     {
-        variableName[ARRAY_SIZE("DOTNET_") - 1 + i] = name[i];
-    }
-#else
-    strcat(variableName, name);
-#endif
+        TCHAR ch = buffer[i];
 
-    cchResult = PalGetEnvironmentVariable(variableName, buffer, cchBuffer);
-    if (cchResult != 0 && cchResult < cchBuffer)
-    {
-        // Environment variable was set. Convert it to an integer.
-        uint64_t uiResult = 0;
-        for (uint32_t i = 0; i < cchResult; i++)
+        if (decimal)
         {
-            TCHAR ch = buffer[i];
+            uiResult *= 10;
 
-            if (decimal)
-            {
-                uiResult *= 10;
-
-                if ((ch >= '0') && (ch <= '9'))
-                    uiResult += ch - '0';
-                else
-                    return false; // parse error
-            }
+            if ((ch >= '0') && (ch <= '9'))
+                uiResult += ch - '0';
             else
-            {
-                uiResult *= 16;
-
-                if ((ch >= '0') && (ch <= '9'))
-                    uiResult += ch - '0';
-                else if ((ch >= 'a') && (ch <= 'f'))
-                    uiResult += (ch - 'a') + 10;
-                else if ((ch >= 'A') && (ch <= 'F'))
-                    uiResult += (ch - 'A') + 10;
-                else
-                    return false; // parse error
-            }
+                return false; // parse error
+        }
+        else
+        {
+            uiResult *= 16;
+
+            if ((ch >= '0') && (ch <= '9'))
+                uiResult += ch - '0';
+            else if ((ch >= 'a') && (ch <= 'f'))
+                uiResult += (ch - 'a') + 10;
+            else if ((ch >= 'A') && (ch <= 'F'))
+                uiResult += (ch - 'A') + 10;
+            else
+                return false; // parse error
         }
+    }
+
+    *value = uiResult;
+    return true;
+}
+
+bool RhConfig::Environment::TryGetStringValue(const char* name, char** value)
+{
+    TCHAR variableName[64];
+    GetEnvironmentConfigName(name, variableName, ARRAY_SIZE(variableName));
+
+    TCHAR buffer[260];
+    uint32_t bufferLen = ARRAY_SIZE(buffer);
+    uint32_t actualLen = PalGetEnvironmentVariable(variableName, buffer, bufferLen);
+    if (actualLen == 0)
+        return false;
 
-        *pValue = uiResult;
+    if (actualLen < bufferLen)
+    {
+        *value = PalCopyTCharAsChar(buffer);
         return true;
     }
 
+    // Expand the buffer to get the value
+    bufferLen = actualLen + 1;
+    NewArrayHolder<TCHAR> newBuffer {new (nothrow) TCHAR[bufferLen]};
+    actualLen = PalGetEnvironmentVariable(variableName, newBuffer, bufferLen);
+    if (actualLen >= bufferLen)
+        return false;
+
+#ifdef TARGET_WINDOWS
+    *value = PalCopyTCharAsChar(newBuffer);
+#else
+    *value = newBuffer.Extract();
+#endif
+    return true;
+}
+
+bool RhConfig::ReadConfigValue(_In_z_ const char *name, uint64_t* pValue, bool decimal)
+{
+    if (Environment::TryGetIntegerValue(name, pValue, decimal))
+        return true;
+
     // Check the embedded configuration
     const char *embeddedValue = nullptr;
     if (GetEmbeddedVariable(name, &embeddedValue))
index 86e8c38..214a79c 100644 (file)
 
 #ifndef DACCESS_COMPILE
 
+#include <sal.h>
+
 class RhConfig
 {
 
 #define CONFIG_INI_NOT_AVAIL (void*)0x1  //signal for ini file failed to load
 #define CONFIG_KEY_MAXLEN 50             //arbitrary max length of config keys increase if needed
 #define CONFIG_VAL_MAXLEN 16              //64 bit uint in hex
-
 private:
     struct ConfigPair
     {
@@ -36,6 +37,15 @@ private:
     void* volatile g_embeddedSettings = NULL;
 
 public:
+    class Environment
+    {
+    public: // static
+        static bool TryGetBooleanValue(const char* name, bool* value);
+        static bool TryGetIntegerValue(const char* name, uint64_t* value, bool decimal = false);
+
+        // Get environment variable configuration as a string. On success, the caller owns the returned string value.
+        static bool TryGetStringValue(const char* name, char** value);
+    };
 
     bool ReadConfigValue(_In_z_ const char* wszName, uint64_t* pValue, bool decimal = false);
 
index a343a18..56200d8 100644 (file)
@@ -3,6 +3,9 @@
 #ifndef __SPINLOCK_H__
 #define __SPINLOCK_H__
 
+// defined in gcrhenv.cpp
+bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount);
+
 // #SwitchToThreadSpinning
 //
 // If you call __SwitchToThread in a loop waiting for a condition to be met,
index 72c040c..c629f2b 100644 (file)
@@ -9,6 +9,14 @@
 #include <eventpipe/ep-stack-contents.h>
 #include <eventpipe/ep-rt.h>
 
+#ifdef TARGET_WINDOWS
+#include <windows.h>
+#else
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
 // 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.
@@ -333,6 +341,73 @@ ep_rt_aot_system_timestamp_get (void)
     return static_cast<int64_t>(((static_cast<uint64_t>(value.dwHighDateTime)) << 32) | static_cast<uint64_t>(value.dwLowDateTime));
 }
 
+ep_rt_file_handle_t
+ep_rt_aot_file_open_write (const ep_char8_t *path)
+{
+    if (!path)
+        return INVALID_HANDLE_VALUE;
+
+#ifdef TARGET_WINDOWS
+    ep_char16_t *path_utf16 = ep_rt_utf8_to_utf16le_string (path, -1);
+    if (!path_utf16)
+        return INVALID_HANDLE_VALUE;
+
+    HANDLE res = ::CreateFileW (reinterpret_cast<LPCWSTR>(path_utf16), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    ep_rt_utf16_string_free (path_utf16);
+    return static_cast<ep_rt_file_handle_t>(res);
+#else
+    mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    int fd = creat (path, perms);
+    if (fd == -1)
+        return INVALID_HANDLE_VALUE;
+
+    return (ep_rt_file_handle_t)(ptrdiff_t)fd;
+#endif
+}
+
+bool
+ep_rt_aot_file_close (ep_rt_file_handle_t file_handle)
+{
+#ifdef TARGET_WINDOWS
+    return ::CloseHandle (file_handle) != FALSE;
+#else
+    int fd = (int)(ptrdiff_t)file_handle;
+    close (fd);
+    return true;
+#endif
+}
+
+bool
+ep_rt_aot_file_write (
+       ep_rt_file_handle_t file_handle,
+       const uint8_t *buffer,
+       uint32_t bytes_to_write,
+       uint32_t *bytes_written)
+{
+#ifdef TARGET_WINDOWS
+    return ::WriteFile (file_handle, buffer, bytes_to_write, reinterpret_cast<LPDWORD>(bytes_written), NULL) != FALSE;
+#else
+    int fd = (int)(ptrdiff_t)file_handle;
+    int ret;
+    do {
+        ret = write (fd, buffer, bytes_to_write);
+    } while (ret == -1 && errno == EINTR);
+
+    if (ret == -1) {
+        if (bytes_written != NULL) {
+            *bytes_written = 0;
+        }
+
+        return false;
+    }
+
+    if (bytes_written != NULL)
+        *bytes_written = ret;
+
+    return true;
+#endif
+}
+
 uint8_t *
 ep_rt_aot_valloc0 (size_t buffer_size)
 {
index ffa5abb..d175665 100644 (file)
@@ -19,6 +19,7 @@
 #include <eventpipe/ep-session-provider.h>
 
 #include "rhassert.h"
+#include <RhConfig.h>
 
 #ifdef TARGET_UNIX
 #define sprintf_s snprintf
@@ -415,11 +416,11 @@ 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
+    // See https://learn.microsoft.com/dotnet/core/diagnostics/eventpipe#trace-using-environment-variables
+    bool value;
+    if (RhConfig::Environment::TryGetBooleanValue("EnableEventPipe", &value))
+        return value;
+
     return false;
 }
 
@@ -429,12 +430,13 @@ 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();
+
+    // See https://learn.microsoft.com/dotnet/core/diagnostics/eventpipe#trace-using-environment-variables
+    char* value;
+    if (RhConfig::Environment::TryGetStringValue("EventPipeConfig", &value))
+        return (ep_char8_t*)value;
+
     return nullptr;
-//    return ep_rt_utf16_to_utf8_string (reinterpret_cast<ep_char16_t *>(value.GetValue ()), -1);
 }
 
 static
@@ -443,10 +445,12 @@ 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();
+
+    // See https://learn.microsoft.com/dotnet/core/diagnostics/eventpipe#trace-using-environment-variables
+    char* value;
+    if (RhConfig::Environment::TryGetStringValue("EventPipeOutputPath", &value))
+        return (ep_char8_t*)value;
+
     return nullptr;
 }
 
@@ -456,10 +460,15 @@ 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();
+
+    // See https://learn.microsoft.com/dotnet/core/diagnostics/eventpipe#trace-using-environment-variables
+    uint64_t value;
+    if (RhConfig::Environment::TryGetIntegerValue("EventPipeCircularMB", &value))
+    {
+        EP_ASSERT(value <= UINT32_MAX);
+        return static_cast<uint32_t>(value);
+    }
+
     return 0;
 }
 
@@ -469,10 +478,11 @@ 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();
+
+    bool value;
+    if (RhConfig::Environment::TryGetBooleanValue("EventPipeOutputStreaming", &value))
+        return value;
+
     return false;
 }
 
@@ -482,10 +492,11 @@ bool
 ep_rt_config_value_get_enable_stackwalk (void)
 {
     STATIC_CONTRACT_NOTHROW;
-    // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
-    // TODO: EventPipe Configuration values - RhConfig?
-    // (CLRConfig::INTERNAL_EventPipeEnableStackwalk)
-    //PalDebugBreak();
+
+    bool value;
+    if (RhConfig::Environment::TryGetBooleanValue("EventPipeEnableStackwalk", &value))
+        return value;
+
     return true;
 }
 
@@ -996,14 +1007,8 @@ 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;
+    extern ep_rt_file_handle_t ep_rt_aot_file_open_write (const ep_char8_t *);
+    return ep_rt_aot_file_open_write (path);
 }
 
 static
@@ -1013,10 +1018,8 @@ 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;
+    extern bool ep_rt_aot_file_close (ep_rt_file_handle_t);
+    return ep_rt_aot_file_close (file_handle);
 }
 
 static
@@ -1031,11 +1034,8 @@ ep_rt_file_write (
     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;
+    extern bool ep_rt_aot_file_write (ep_rt_file_handle_t, const uint8_t*, uint32_t, uint32_t*);
+    return ep_rt_aot_file_write (file_handle, buffer, bytes_to_write, bytes_written);
 }
 
 static
index df06d26..22c777f 100644 (file)
@@ -58,7 +58,7 @@ typedef class MethodDesc ep_rt_method_desc_t;
  */
 
 #undef ep_rt_file_handle_t
-typedef class CFileStream * ep_rt_file_handle_t;
+typedef void * 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;
index e950a1e..a856be4 100644 (file)
@@ -738,6 +738,13 @@ REDHAWK_PALEXPORT void PalPrintFatalError(const char* message)
     (void)!write(STDERR_FILENO, message, strlen(message));
 }
 
+REDHAWK_PALEXPORT char* PalCopyTCharAsChar(const TCHAR* toCopy)
+{
+    NewArrayHolder<char> copy {new (nothrow) char[strlen(toCopy) + 1]};
+    strcpy(copy, toCopy);
+    return copy.Extract();
+}
+
 static int W32toUnixAccessControl(uint32_t flProtect)
 {
     int prot = 0;
index c6a0082..c7b1f3e 100644 (file)
 
 #define PalRaiseFailFastException RaiseFailFastException
 
-uint32_t PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t arg3, EVENT_DATA_DESCRIPTOR * arg4)
-{
-    return EventWrite(arg1, arg2, arg3, arg4);
-}
-
 #include "gcenv.h"
 #include "gcenv.ee.h"
 #include "gcconfig.h"
@@ -634,6 +629,21 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalEventEnabled(REGHANDLE regHandle, _In_
     return !!EventEnabled(regHandle, eventDescriptor);
 }
 
+REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI PalEventRegister(const GUID * arg1, void * arg2, void * arg3, REGHANDLE * arg4)
+{
+    return EventRegister(arg1, reinterpret_cast<PENABLECALLBACK>(arg2), arg3, arg4);
+}
+
+REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI PalEventUnregister(REGHANDLE arg1)
+{
+    return EventUnregister(arg1);
+}
+
+REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t arg3, EVENT_DATA_DESCRIPTOR * arg4)
+{
+    return EventWrite(arg1, arg2, arg3, arg4);
+}
+
 REDHAWK_PALEXPORT void REDHAWK_PALAPI PalTerminateCurrentProcess(uint32_t arg2)
 {
     TerminateProcess(GetCurrentProcess(), arg2);
@@ -719,6 +729,18 @@ REDHAWK_PALEXPORT void PalPrintFatalError(const char* message)
     WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, (DWORD)strlen(message), &dwBytesWritten, NULL);
 }
 
+REDHAWK_PALEXPORT char* PalCopyTCharAsChar(const TCHAR* toCopy)
+{
+    int len = ::WideCharToMultiByte(CP_UTF8, 0, toCopy, -1, nullptr, 0, nullptr, nullptr);
+    if (len == 0)
+        return nullptr;
+
+    char* converted = new (nothrow) char[len];
+    int written = ::WideCharToMultiByte(CP_UTF8, 0, toCopy, -1, converted, len, nullptr, nullptr);
+    assert(len == written);
+    return converted;
+}
+
 REDHAWK_PALEXPORT _Ret_maybenull_ _Post_writable_byte_size_(size) void* REDHAWK_PALAPI PalVirtualAlloc(_In_opt_ void* pAddress, uintptr_t size, uint32_t allocationType, uint32_t protect)
 {
     return VirtualAlloc(pAddress, size, allocationType, protect);
index b7fc2b4..4ce8e15 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/buffersize/**">
             <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
         </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/config/**">
-            <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/diagnosticport/**">
             <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
         </ExcludeList>
index 779d945..edd8945 100644 (file)
@@ -9,6 +9,7 @@ using System.Threading;
 
 class NameConfigWithPid
 {
+    private const string WaitForInput = "waitforinput";
     static int Main(string[] args)
     {
         if (args.Length == 0)
@@ -16,7 +17,7 @@ class NameConfigWithPid
         else
             Console.WriteLine($"args[0] = `{args[0]}`");
 
-        if (args.Length > 0 && args[0] == "waitforinput")
+        if (args.Length > 0 && args[0] == WaitForInput)
         {
             Console.Error.WriteLine("WaitingForInput in ErrorStream");
             Console.WriteLine("WaitingForInput");
@@ -39,17 +40,16 @@ class NameConfigWithPid
             }
 
             string coreRoot = Environment.GetEnvironmentVariable("CORE_ROOT");
-            string corerun = Path.Combine(coreRoot, "corerun");
-            if (OperatingSystem.IsWindows())
-                corerun = corerun + ".exe";
 
-            // Use dll directory as temp directory
-            string tempDir = Path.GetDirectoryName(typeof(NameConfigWithPid).Assembly.Location);
+            // Use app directory as temp directory
+            string tempDir = AppContext.BaseDirectory;
             string outputPathBaseName = $"eventPipeStream{Thread.CurrentThread.ManagedThreadId}_{(ulong)Stopwatch.GetTimestamp()}";
             string outputPathPattern = Path.Combine(tempDir, outputPathBaseName + "_{pid}_{pid}.nettrace");
 
-            process.StartInfo.FileName = corerun;
-            process.StartInfo.Arguments = typeof(NameConfigWithPid).Assembly.Location + " waitforinput";
+            process.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
+            process.StartInfo.Arguments = TestLibrary.Utilities.IsNativeAot
+                ? WaitForInput
+                : $"{typeof(NameConfigWithPid).Assembly.Location} {WaitForInput}";
             process.StartInfo.UseShellExecute = false;
             process.StartInfo.RedirectStandardInput = true;
             process.StartInfo.RedirectStandardError = true;
@@ -63,7 +63,7 @@ class NameConfigWithPid
             Console.Out.Flush();
             process.Start();
 
-            string readFromTargetProcess = process.StandardError.ReadLine(); 
+            string readFromTargetProcess = process.StandardError.ReadLine();
             Console.WriteLine($"Readline '{readFromTargetProcess}'");
             if (readFromTargetProcess != "WaitingForInput in ErrorStream")
             {
@@ -101,7 +101,7 @@ class NameConfigWithPid
                     Thread.Sleep(1000);
                 }
                 Console.WriteLine($"Unable to delete {expectedPath}");
-                return 2; 
+                return 2;
             }
         }
     }
index 6089c06..187b430 100644 (file)
@@ -5,8 +5,10 @@
     <!-- Tracing tests routinely time out with jitstress and gcstress -->
     <GCStressIncompatible>true</GCStressIncompatible>
     <JitOptimizationSensitive>true</JitOptimizationSensitive>
+    <EventSourceSupport Condition="'$(TestBuildMode)' == 'nativeaot'">true</EventSourceSupport>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="$(MSBuildProjectName).cs" />
+    <ProjectReference Include="$(TestSourceDir)Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj" />
   </ItemGroup>
 </Project>