From 897efbfc890d31d45a447ded6a75604142b181e5 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 29 Jan 2026 22:31:31 +0000 Subject: [PATCH 1/3] [EventPipe] Add dotnet_ipc_created mapping --- src/native/eventpipe/configure.cmake | 16 +++++++++++++++ src/native/eventpipe/ds-ipc.c | 23 +++++++++++++++++++++- src/native/eventpipe/ep-shared-config.h.in | 2 ++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/native/eventpipe/configure.cmake b/src/native/eventpipe/configure.cmake index 8bb378efd3f20d..294a6767e3d783 100644 --- a/src/native/eventpipe/configure.cmake +++ b/src/native/eventpipe/configure.cmake @@ -28,6 +28,11 @@ check_include_file( HAVE_SYS_IOCTL_H ) +check_include_file( + sys/syscall.h + HAVE_SYS_SYSCALL_H +) + check_include_file( unistd.h HAVE_UNISTD_H @@ -43,6 +48,17 @@ check_include_file( HAVE_ERRNO_H ) +check_include_file( + sys/mman.h + HAVE_SYS_MMAN_H +) + +check_symbol_exists( + __NR_memfd_create + sys/syscall.h + HAVE_MEMFD_CREATE +) + if (NOT DEFINED EP_GENERATED_HEADER_PATH) message(FATAL_ERROR "Required configuration EP_GENERATED_HEADER_PATH not set.") endif (NOT DEFINED EP_GENERATED_HEADER_PATH) diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index cb2b051cb9ed20..d63f0a0479744c 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -10,6 +10,15 @@ #include "ep.h" #include "ds-rt.h" +#if HAVE_SYS_MMAN_H && HAVE_MEMFD_CREATE && HAVE_UNISTD_H +#include +#include +#include +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif +#endif + /* * Globals and volatile access functions. */ @@ -332,7 +341,19 @@ ds_ipc_stream_factory_configure (ds_ipc_error_callback_func callback) default_port_builder.suspend_mode = port_suspend > 0 ? DS_PORT_SUSPEND_MODE_SUSPEND : DS_PORT_SUSPEND_MODE_NOSUSPEND; default_port_builder.type = DS_PORT_TYPE_LISTEN; - result &= ipc_stream_factory_build_and_add_port (&default_port_builder, callback, true); + bool default_listen_port_ready = ipc_stream_factory_build_and_add_port (&default_port_builder, callback, true); +#if HAVE_SYS_MMAN_H && HAVE_MEMFD_CREATE && HAVE_UNISTD_H + // Create a mapping to signal that the diagnostic server IPC is available. + // External tools can use this to detect when the runtime is ready to accept diagnostic commands. + if (default_listen_port_ready) { + int fd = (int)syscall (__NR_memfd_create, "dotnet_ipc_created", (unsigned int)MFD_CLOEXEC); + if (fd >= 0) { + mmap (NULL, 1, PROT_EXEC | PROT_READ, MAP_PRIVATE, fd, 0); + close (fd); + } + } +#endif + result &= default_listen_port_ready; ds_port_builder_fini (&default_port_builder); } else { diff --git a/src/native/eventpipe/ep-shared-config.h.in b/src/native/eventpipe/ep-shared-config.h.in index 0eeb73e1dcb4f2..025bbab83a557e 100644 --- a/src/native/eventpipe/ep-shared-config.h.in +++ b/src/native/eventpipe/ep-shared-config.h.in @@ -2,6 +2,8 @@ #define EP_SHARED_CONFIG_H_INCLUDED #cmakedefine01 HAVE_ERRNO_H +#cmakedefine01 HAVE_SYS_MMAN_H +#cmakedefine01 HAVE_MEMFD_CREATE #cmakedefine01 HAVE_LINUX_USER_EVENTS_H #cmakedefine01 HAVE_SYS_IOCTL_H #cmakedefine01 HAVE_SYS_SOCKET_H From d2850f2d8f216697dfcb98c6ea025286fa9c3fb8 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 29 Jan 2026 23:15:49 +0000 Subject: [PATCH 2/3] Add mapping lifetime comment --- src/native/eventpipe/ds-ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index d63f0a0479744c..5bdbce07825f8e 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -345,6 +345,7 @@ ds_ipc_stream_factory_configure (ds_ipc_error_callback_func callback) #if HAVE_SYS_MMAN_H && HAVE_MEMFD_CREATE && HAVE_UNISTD_H // Create a mapping to signal that the diagnostic server IPC is available. // External tools can use this to detect when the runtime is ready to accept diagnostic commands. + // The mapping's lifetime is tied to the process, so tools that start after the .NET process can still detect it. if (default_listen_port_ready) { int fd = (int)syscall (__NR_memfd_create, "dotnet_ipc_created", (unsigned int)MFD_CLOEXEC); if (fd >= 0) { From 1918437c42e188891a0082ca4cf58d24b44ba883 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 30 Jan 2026 17:38:19 +0000 Subject: [PATCH 3/3] Create mapping for any listen port --- src/native/eventpipe/ds-ipc.c | 39 ++++++++++++++++++++++------------- src/native/eventpipe/ds-ipc.h | 3 +++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index 5bdbce07825f8e..05cddd7618c7cc 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -341,20 +341,7 @@ ds_ipc_stream_factory_configure (ds_ipc_error_callback_func callback) default_port_builder.suspend_mode = port_suspend > 0 ? DS_PORT_SUSPEND_MODE_SUSPEND : DS_PORT_SUSPEND_MODE_NOSUSPEND; default_port_builder.type = DS_PORT_TYPE_LISTEN; - bool default_listen_port_ready = ipc_stream_factory_build_and_add_port (&default_port_builder, callback, true); -#if HAVE_SYS_MMAN_H && HAVE_MEMFD_CREATE && HAVE_UNISTD_H - // Create a mapping to signal that the diagnostic server IPC is available. - // External tools can use this to detect when the runtime is ready to accept diagnostic commands. - // The mapping's lifetime is tied to the process, so tools that start after the .NET process can still detect it. - if (default_listen_port_ready) { - int fd = (int)syscall (__NR_memfd_create, "dotnet_ipc_created", (unsigned int)MFD_CLOEXEC); - if (fd >= 0) { - mmap (NULL, 1, PROT_EXEC | PROT_READ, MAP_PRIVATE, fd, 0); - close (fd); - } - } -#endif - result &= default_listen_port_ready; + result &= ipc_stream_factory_build_and_add_port (&default_port_builder, callback, true); ds_port_builder_fini (&default_port_builder); } else { @@ -364,6 +351,19 @@ ds_ipc_stream_factory_configure (ds_ipc_error_callback_func callback) DS_LOG_DEBUG_0 ("ds_ipc_stream_factory_configure - Ignoring default LISTEN port"); #endif +#if HAVE_SYS_MMAN_H && HAVE_MEMFD_CREATE && HAVE_UNISTD_H + // Create a mapping to signal that the diagnostic server IPC is available. + // External tools can use this to detect when the runtime is ready to accept diagnostic commands. + // The mapping's lifetime is tied to the process, so tools that start after the .NET process can still detect it. + if (ds_ipc_stream_factory_any_listen_ports ()) { + int fd = (int)syscall (__NR_memfd_create, "dotnet_ipc_created", (unsigned int)MFD_CLOEXEC); + if (fd >= 0) { + mmap (NULL, 1, PROT_EXEC | PROT_READ, MAP_PRIVATE, fd, 0); + close (fd); + } + } +#endif + return result; } @@ -501,6 +501,17 @@ ds_ipc_stream_factory_resume_current_port (void) _ds_current_port->has_resumed_runtime = true; } +bool +ds_ipc_stream_factory_any_listen_ports (void) +{ + bool any_listen_ports = false; + DN_VECTOR_PTR_FOREACH_BEGIN (DiagnosticsPort *, port, _ds_port_array) { + any_listen_ports |= (port->type == DS_PORT_TYPE_LISTEN); + } DN_VECTOR_PTR_FOREACH_END; + + return any_listen_ports; +} + bool ds_ipc_stream_factory_any_suspended_ports (void) { diff --git a/src/native/eventpipe/ds-ipc.h b/src/native/eventpipe/ds-ipc.h index 7da0c5d75f300e..a13e82c8403bbc 100644 --- a/src/native/eventpipe/ds-ipc.h +++ b/src/native/eventpipe/ds-ipc.h @@ -32,6 +32,9 @@ ds_ipc_stream_factory_get_next_available_stream (ds_ipc_error_callback_func call void ds_ipc_stream_factory_resume_current_port (void); +bool +ds_ipc_stream_factory_any_listen_ports (void); + bool ds_ipc_stream_factory_any_suspended_ports (void);