Handle diagnostic port configuration in NativeAOT (#87088)
authorElinor Fung <elfung@microsoft.com>
Thu, 8 Jun 2023 04:43:43 +0000 (21:43 -0700)
committerGitHub <noreply@github.com>
Thu, 8 Jun 2023 04:43:43 +0000 (21:43 -0700)
eng/pipelines/runtime.yml
src/coreclr/nativeaot/Runtime/RhConfig.h
src/coreclr/nativeaot/Runtime/eventpipe/ds-rt-aot.h
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp
src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h
src/tests/issues.targets
src/tests/tracing/eventpipe/common/IpcUtils.cs
src/tests/tracing/eventpipe/common/common.csproj
src/tests/tracing/eventpipe/diagnosticport/diagnosticport.cs
src/tests/tracing/eventpipe/diagnosticport/diagnosticport.csproj
src/tests/tracing/eventpipe/reverse/reverse.csproj

index 9fe2862..4b182fb 100644 (file)
@@ -248,7 +248,7 @@ extends:
             extraStepsTemplate: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
             extraStepsParameters:
               creator: dotnet-bot
-              testBuildArgs: 'nativeaot tree ";nativeaot;Loader;Interop;tracing/eventpipe/config;" test tracing/eventcounter/runtimecounters.csproj /p:BuildNativeAotFrameworkObjects=true'
+              testBuildArgs: 'nativeaot tree ";nativeaot;Loader;Interop;tracing/eventpipe/config;tracing/eventpipe/diagnosticport;tracing/eventpipe/reverse;" test tracing/eventcounter/runtimecounters.csproj /p:BuildNativeAotFrameworkObjects=true'
               liveLibrariesBuildConfig: Release
             testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
             extraVariablesTemplates:
index 5d56f57..59d1d37 100644 (file)
@@ -11,6 +11,8 @@
 // Values can also be embedded in the compiled binary.
 //
 
+#ifndef RHCONFIG_H
+#define RHCONFIG_H
 
 #ifndef DACCESS_COMPILE
 
@@ -108,3 +110,5 @@ private:
 extern RhConfig * g_pRhConfig;
 
 #endif //!DACCESS_COMPILE
+
+#endif // RHCONFIG_H
index aaea673..9a56a52 100644 (file)
@@ -13,6 +13,8 @@
 #include <eventpipe/ds-profiler-protocol.h>
 #include <eventpipe/ds-dump-protocol.h>
 
+#include <RhConfig.h>
+
 #undef DS_LOG_ALWAYS_0
 #define DS_LOG_ALWAYS_0(msg) do {} while (0)
 
@@ -127,8 +129,10 @@ 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?
+    bool value;
+    if (RhConfig::Environment::TryGetBooleanValue("EnableDiagnostics", &value))
+        return value;
+
     return true;
 }
 
@@ -137,8 +141,12 @@ 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?
+    STATIC_CONTRACT_NOTHROW;
+
+    char* value;
+    if (RhConfig::Environment::TryGetStringValue("DiagnosticPorts", &value))
+        return (ep_char8_t*)value;
+
     return nullptr;
 }
 
@@ -148,8 +156,14 @@ 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?
+    
+    uint64_t value;
+    if (RhConfig::Environment::TryGetIntegerValue("DefaultDiagnosticPortSuspend", &value))
+    {
+        EP_ASSERT(value <= UINT32_MAX);
+        return static_cast<uint32_t>(value);
+    }
+
     return 0;
 }
 
@@ -281,10 +295,15 @@ 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();
+    ep_char8_t * ports = ds_rt_config_value_get_ports ();
+       uint32_t port_suspended = ds_rt_config_value_get_default_port_suspend ();
+
+       printf ("The runtime has been configured to pause during startup and is awaiting a Diagnostics IPC ResumeStartup command from a Diagnostic Port.\n");
+       printf ("DOTNET_DiagnosticPorts=\"%s\"\n", ports == nullptr ? "" : ports);
+       printf ("DOTNET_DefaultDiagnosticPortSuspend=%d\n", port_suspended);
+       fflush (stdout);
+
+       ep_rt_utf8_string_free (ports);
 }
 
 #endif /* ENABLE_PERFTRACING */
index c629f2b..f7793b4 100644 (file)
@@ -90,13 +90,22 @@ 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<const ep_char8_t*>("");
 }
 
+const ep_char8_t *
+ep_rt_aot_diagnostics_command_line_get (void)
+{
+    // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
+    // TODO: revisit commandline for AOT
+#ifdef TARGET_WINDOWS
+    const ep_char16_t* command_line = reinterpret_cast<const ep_char16_t *>(::GetCommandLineW());
+    return ep_rt_utf16_to_utf8_string(command_line, -1);
+#else
+    return "";
+#endif
+}
+
 uint32_t
 ep_rt_aot_atomic_inc_uint32_t (volatile uint32_t *value)
 {
index d175665..2687fc8 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "rhassert.h"
 #include <RhConfig.h>
+#include <runtime_version.h>
 
 #ifdef TARGET_UNIX
 #define sprintf_s snprintf
@@ -47,6 +48,9 @@
 #undef EP_ALIGN_UP
 #define EP_ALIGN_UP(val,align) _rt_aot_align_up(val,align)
 
+#define _TEXT(s) #s
+#define STRINGIFY(s) _TEXT(s)
+
 #ifdef TARGET_UNIX
 extern pthread_key_t eventpipe_tls_key;
 extern __thread EventPipeThreadHolder* eventpipe_tls_instance;
@@ -88,12 +92,11 @@ ep_rt_entrypoint_assembly_name_get_utf8 (void)
 
 static
 const ep_char8_t *
-ep_rt_runtime_version_get_utf8 (void) { 
+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<const ep_char8_t*>("8.0.0");
+    return reinterpret_cast<const ep_char8_t*>(STRINGIFY(RuntimeProductVersion));
 }
 
 /*
@@ -1388,10 +1391,7 @@ ep_rt_utf8_to_utf16le_string (
     // Shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
     // Implementation would just use strlen and malloc to make a new buffer, and would then copy the string chars one by one.
     // Assumes that only ASCII is used for ep_char8_t
-    size_t len_utf8 = strlen(str);        
-    if (len_utf8 == 0)
-        return NULL;
-
+    size_t len_utf8 = strlen(str);
     ep_char16_t *str_utf16 = reinterpret_cast<ep_char16_t *>(malloc ((len_utf8 + 1) * sizeof (ep_char16_t)));
     if (!str_utf16)
         return NULL;
@@ -1511,16 +1511,9 @@ 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<const ep_char8_t *>(::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;
+    extern const ep_char8_t * ep_rt_aot_diagnostics_command_line_get (void);
+    return ep_rt_aot_diagnostics_command_line_get();
 }
 
 /*
index fb94709..8d1f645 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/buffersize/**">
             <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>
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/enabledisable/**">
             <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
         </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/providervalidation/**">
             <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
         </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/reverse/**">
-            <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/reverseouter/**">
             <Issue>https://github.com/dotnet/runtime/issues/83051</Issue>
         </ExcludeList>
index e2130f4..69c3846 100644 (file)
@@ -73,7 +73,7 @@ namespace Tracing.Tests.Common
                 foreach ((string key, string value) in environment)
                     process.StartInfo.Environment.Add(key, value);
                 process.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
-                process.StartInfo.Arguments = new Uri(currentAssembly.Location).LocalPath + " 0";
+                process.StartInfo.Arguments = TestLibrary.Utilities.IsNativeAot ? "0" : $"{new Uri(currentAssembly.Location).LocalPath} 0";
                 process.StartInfo.RedirectStandardOutput = true;
                 process.StartInfo.RedirectStandardInput = true;
                 process.StartInfo.RedirectStandardError = true;
index 98bdde8..3c701df 100644 (file)
@@ -18,5 +18,6 @@
     <Compile Include="Reverse.cs" />
     <Compile Include="StreamProxy.cs" />
     <ProjectReference Include="Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj" />
+    <ProjectReference Include="$(TestSourceDir)Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj" />
   </ItemGroup>
 </Project>
index 7511acd..a1c08d4 100644 (file)
@@ -109,67 +109,29 @@ namespace Tracing.Tests.DiagnosticPortValidation
                 duringExecution: async (int pid) =>
                 {
                     subprocessId = pid;
-                    // Create an eventpipe session that will tell us when
-                    // the EEStartupStarted event happens.  This will tell us
-                    // the runtime has been resumed.  This should only happen
-                    // AFTER all suspend ports have sent the resume command.
-                    var config = new SessionConfiguration(
-                        circularBufferSizeMB: 1000,
-                        format: EventPipeSerializationFormat.NetTrace,
-                        providers: new List<Provider> {
-                            new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose),
-                            // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the
-                            // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent)
-                            // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent).
-                            // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data
-                            // that won't come otherwise.
-                            new Provider("Microsoft-DotNETCore-SampleProfiler")
-                        });
-                    Logger.logger.Log("Starting EventPipeSession over standard connection");
-                    using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
-                    Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");
 
                     var mre = new ManualResetEvent(false);
-
-                    Task readerTask = Task.Run(async () =>
-                    {
-                        Logger.logger.Log($"Creating EventPipeEventSource");
-                        using var source = new EventPipeEventSource(eventStream);
-                        var parser = new ClrPrivateTraceEventParser(source);
-                        parser.StartupEEStartupStart += (eventData) => mre.Set();
-                        Logger.logger.Log($"Created EventPipeEventSource");
-                        Logger.logger.Log($"Starting processing");
-                        await Task.Run(() => source.Process());
-                        Logger.logger.Log($"Finished processing");
-                    });
-
-                    for (int i = 0; i < s_NumberOfPorts; i++)
+                    await ConfigureAndWaitForResumeSignal(pid, mre, async () =>
                     {
-                        fSuccess &= !mre.WaitOne(0);
-                        Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");
-                        var (server, _) = serverAndNames[i];
-                        int serverIndex = i;
-                        Stream stream = await server.AcceptAsync();
-                        IpcAdvertise advertise = IpcAdvertise.Parse(stream);
-                        lock(sync)
-                            advertisements.Add(advertise);
-                        Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}");
-
-                        // send resume command on this connection
-                        var message = new IpcMessage(0x04,0x01);
-                        Logger.logger.Log($"Port {serverIndex} sent: {message.ToString()}");
-                        IpcMessage response = IpcClient.SendMessage(stream, message);
-                        Logger.logger.Log($"Port {serverIndex} received: {response.ToString()}");
-                    }
-
-                    Logger.logger.Log($"Waiting on EEStartupStarted event");
-                    mre.WaitOne();
-                    Logger.logger.Log($"Saw EEStartupStarted Event");
+                        for (int i = 0; i < s_NumberOfPorts; i++)
+                        {
+                            fSuccess &= !mre.WaitOne(0);
+                            Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");
+                            var (server, _) = serverAndNames[i];
+                            int serverIndex = i;
+                            Stream stream = await server.AcceptAsync();
+                            IpcAdvertise advertise = IpcAdvertise.Parse(stream);
+                            lock(sync)
+                                advertisements.Add(advertise);
+                            Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}");
 
-                    Logger.logger.Log($"Stopping EventPipeSession");
-                    EventPipeClient.StopTracing(pid, sessionId);
-                    await readerTask;
-                    Logger.logger.Log($"Stopped EventPipeSession");
+                            // send resume command on this connection
+                            var message = new IpcMessage(0x04,0x01);
+                            Logger.logger.Log($"Port {serverIndex} sent: {message.ToString()}");
+                            IpcMessage response = IpcClient.SendMessage(stream, message);
+                            Logger.logger.Log($"Port {serverIndex} received: {response.ToString()}");
+                        }
+                    });
 
                     // runtime should have resumed now
                     fSuccess &= mre.WaitOne(0);
@@ -204,7 +166,6 @@ namespace Tracing.Tests.DiagnosticPortValidation
         {
             bool fSuccess = true;
 
-            int subprocessId = -1;
             Task<bool> subprocessTask = Utils.RunSubprocess(
                 currentAssembly: Assembly.GetExecutingAssembly(),
                 environment: new Dictionary<string,string>
@@ -213,73 +174,100 @@ namespace Tracing.Tests.DiagnosticPortValidation
                 },
                 duringExecution: async (int pid) =>
                 {
-                    subprocessId = pid;
-                    // Create an eventpipe session that will tell us when
-                    // the EEStartupStarted event happens.  This will tell us
-                    // the runtime has been resumed.  This should only happen
-                    // AFTER all suspend ports have sent the resume command.
-                    var config = new SessionConfiguration(
-                        circularBufferSizeMB: 1000,
-                        format: EventPipeSerializationFormat.NetTrace,
-                        providers: new List<Provider> {
-                            new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose),
-                            // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the
-                            // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent)
-                            // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent).
-                            // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data
-                            // that won't come otherwise.
-                            new Provider("Microsoft-DotNETCore-SampleProfiler")
-                        });
-                    Logger.logger.Log("Starting EventPipeSession over standard connection");
-                    using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
-                    Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");
-
                     var mre = new ManualResetEvent(false);
-
-                    Task readerTask = Task.Run(async () =>
+                    await ConfigureAndWaitForResumeSignal(pid, mre, () =>
                     {
-                        Logger.logger.Log($"Creating EventPipeEventSource");
-                        using var source = new EventPipeEventSource(eventStream);
-                        var parser = new ClrPrivateTraceEventParser(source);
-                        parser.StartupEEStartupStart += (eventData) => mre.Set();
-                        Logger.logger.Log($"Created EventPipeEventSource");
-                        Logger.logger.Log($"Starting processing");
-                        await Task.Run(() => source.Process());
-                        Logger.logger.Log($"Finished processing");
-                    });
-
-
-                    fSuccess &= !mre.WaitOne(0);
-                    Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");
-
-                    // send resume command on this connection
-                    var message = new IpcMessage(0x04,0x01);
-                    Logger.logger.Log($"Sent: {message.ToString()}");
-                    IpcMessage response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(pid), message);
-                    Logger.logger.Log($"Received: {response.ToString()}");
-
-                    Logger.logger.Log($"Waiting for EEStartupStarted event");
-                    mre.WaitOne();
-                    Logger.logger.Log($"Saw EEStartupStarted event!");
+                        fSuccess &= !mre.WaitOne(0);
+                        Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}");
 
-                    Logger.logger.Log($"Stopping EventPipeSession");
-                    EventPipeClient.StopTracing(pid, sessionId);
-                    await readerTask;
-                    Logger.logger.Log($"Stopped EventPipeSession");
+                        // send resume command on this connection
+                        var message = new IpcMessage(0x04,0x01);
+                        Logger.logger.Log($"Sent: {message.ToString()}");
+                        IpcMessage response = IpcClient.SendMessage(ConnectionHelper.GetStandardTransport(pid), message);
+                        Logger.logger.Log($"Received: {response.ToString()}");
+                        return Task.CompletedTask;
+                    });
 
                     // runtime should have resumed now
                     fSuccess &= mre.WaitOne(0);
                     Logger.logger.Log($"Runtime HAS resumed (expects: true): {fSuccess}");
-
                 }
             );
 
-
             fSuccess &= await subprocessTask;
 
             return fSuccess;
         }
 
+        private static async Task ConfigureAndWaitForResumeSignal(int pid, ManualResetEvent mre, Func<Task> resumeRuntime)
+        {
+            var providers = new List<Provider>(2);
+            if (TestLibrary.Utilities.IsNativeAot)
+            {
+                // Native AOT doesn't use the private provider / EEStartupStart event, so the subprocess
+                // writes a sentinel event to signal that the runtime has resumed and run the application 
+                providers.Add(new Provider(nameof(SentinelEventSource)));
+            }
+            else
+            {
+                providers.Add(new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose));
+            }
+
+            // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the
+            // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent)
+            // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent).
+            // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data
+            // that won't come otherwise.
+            providers.Add(new Provider("Microsoft-DotNETCore-SampleProfiler"));
+
+            // Create an eventpipe session with prodiers that tell us
+            // the runtime has been resumed.  This should only happen
+            // AFTER all suspend ports have sent the resume command.
+            var config = new SessionConfiguration(
+                circularBufferSizeMB: 1000,
+                format: EventPipeSerializationFormat.NetTrace,
+                providers: providers);
+            Logger.logger.Log("Starting EventPipeSession over standard connection");
+            using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId);
+            Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}");
+
+            Task readerTask = Task.Run(async () =>
+            {
+                Logger.logger.Log($"Creating EventPipeEventSource");
+                using var source = new EventPipeEventSource(eventStream);
+                ClrPrivateTraceEventParser parser;
+                if (TestLibrary.Utilities.IsNativeAot)
+                {
+                    source.Dynamic.All += (eventData) =>
+                    {
+                        if (eventData.ProviderName == nameof(SentinelEventSource))
+                            mre.Set();
+                    };
+                }
+                else
+                {
+                    parser = new ClrPrivateTraceEventParser(source);
+                    parser.StartupEEStartupStart += (eventData) => mre.Set();
+                }
+
+                Logger.logger.Log($"Starting processing");
+                await Task.Run(() => source.Process());
+                Logger.logger.Log($"Finished processing");
+            });
+
+            await resumeRuntime();
+
+            string resumeEventName = TestLibrary.Utilities.IsNativeAot ? nameof(SentinelEventSource) : "EEStartupStart";
+            Logger.logger.Log($"Waiting for runtime resume signal event ({resumeEventName})");
+            mre.WaitOne();
+            Logger.logger.Log($"Saw runtime resume signal event!");
+
+            Logger.logger.Log($"Stopping EventPipeSession");
+            EventPipeClient.StopTracing(pid, sessionId);
+            await readerTask;
+            Logger.logger.Log($"Stopped EventPipeSession");
+        }
+
         public static async Task<bool> TEST_AdvertiseAndProcessInfoCookiesMatch()
         {
             bool fSuccess = true;
@@ -408,11 +396,18 @@ namespace Tracing.Tests.DiagnosticPortValidation
                     Logger.logger.Log($"Received: [{response.Payload.Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
                     ProcessInfo2 processInfo2 = ProcessInfo2.TryParse(response.Payload);
 
-                    if (Type.GetType("Mono.RuntimeStructs") != null)
+                    if (TestLibrary.Utilities.IsMonoRuntime)
                     {
                         // Mono currently returns empty string if the runtime is suspended before an assembly is loaded
                         Utils.Assert(string.IsNullOrEmpty(processInfo2.ManagedEntrypointAssemblyName));
                     }
+                    else if (TestLibrary.Utilities.IsNativeAot)
+                    {
+                        // shipping criteria: no EVENTPIPE-NATIVEAOT-TODO left in the codebase
+                        // https://github.com/dotnet/runtime/issues/83051
+                        // NativeAOT currently always returns empty string
+                        Utils.Assert(processInfo2.ManagedEntrypointAssemblyName == string.Empty);
+                    }
                     else
                     {
                         // Assembly has not been loaded yet, so the assembly file name is used
@@ -436,10 +431,21 @@ namespace Tracing.Tests.DiagnosticPortValidation
             return fSuccess;
         }
 
+        public sealed class SentinelEventSource : EventSource
+        {
+            private SentinelEventSource() {}
+            public static SentinelEventSource Log = new SentinelEventSource();
+            public void SentinelEvent() { WriteEvent(1, nameof(SentinelEvent)); }
+        }
+
         public static async Task<int> Main(string[] args)
         {
             if (args.Length >= 1)
             {
+                // Native AOT test uses this event source as a signal that the runtime has resumed and gone on to run the application 
+                if (TestLibrary.Utilities.IsNativeAot)
+                    SentinelEventSource.Log.SentinelEvent();
+
                 Console.Out.WriteLine("Subprocess started!  Waiting for input...");
                 var input = Console.In.ReadLine(); // will block until data is sent across stdin
                 Console.Out.WriteLine($"Received '{input}'.  Exiting...");
index c20471b..2dd6c13 100644 (file)
@@ -7,9 +7,11 @@
     <!-- 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="../common/common.csproj" />
+    <ProjectReference Include="$(TestSourceDir)Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj" />
   </ItemGroup>
 </Project>
index a2fca0e..4b4bae0 100644 (file)
@@ -8,6 +8,7 @@
     <!-- 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" />