From 806b6e75d23df83c283a0eafeac4107fd8b8d548 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 11 Aug 2026 00:02:33 -0400 Subject: [PATCH 1/6] System.IO.Compression.Native: link minipal Link the shared library against minipal so externally defined helpers are resolved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/libs/System.IO.Compression.Native/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt index c105ffe5b0c586..d3a1132b5faf6c 100644 --- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt +++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt @@ -251,6 +251,10 @@ else () endif () +if (TARGET System.IO.Compression.Native) + target_link_libraries(System.IO.Compression.Native PRIVATE minipal) +endif() + install (TARGETS System.IO.Compression.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) if(CLR_CMAKE_HOST_ANDROID OR CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_MACCATALYST OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) From 95a8da574533173ab5b78307daba9b784118dca6 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 11 Aug 2026 00:02:59 -0400 Subject: [PATCH 2/6] minipal: add external fallbacks for inline header helpers Keep helper implementations inline in headers while providing one external definition for callers when the compiler does not inline them. Move the shared thread ID TLS cache to thread.c. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/CMakeLists.txt | 1 + src/native/minipal/entrypoints.c | 6 ++++++ src/native/minipal/entrypoints.h | 10 +++++++++- src/native/minipal/thread.c | 12 ++++++++++-- src/native/minipal/thread.h | 6 +++--- 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/native/minipal/entrypoints.c diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index bd219f66c97e2f..ce8bbd0c4035d8 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -5,6 +5,7 @@ include(configure.cmake) set(SOURCES cpufeatures.c descriptorlimit.c + entrypoints.c memorybarrierprocesswide.c mutex.c guid.c diff --git a/src/native/minipal/entrypoints.c b/src/native/minipal/entrypoints.c new file mode 100644 index 00000000000000..7af669924dac62 --- /dev/null +++ b/src/native/minipal/entrypoints.c @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "entrypoints.h" + +extern const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name); diff --git a/src/native/minipal/entrypoints.h b/src/native/minipal/entrypoints.h index 5ef45699cacdf1..65f1f114741d89 100644 --- a/src/native/minipal/entrypoints.h +++ b/src/native/minipal/entrypoints.h @@ -18,7 +18,11 @@ typedef struct #define DllImportEntry(impl) \ {#impl, (void*)&impl}, -static const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name) +#ifdef __cplusplus +extern "C" { +#endif + +inline const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name) { for (size_t i = 0; i < tableLength; i++) { @@ -31,4 +35,8 @@ static const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_ return NULL; } +#ifdef __cplusplus +} +#endif // extern "C" + #endif // HAVE_MINIPAL_ENTRYPOINTS_H diff --git a/src/native/minipal/thread.c b/src/native/minipal/thread.c index 8e86796289d46c..0d1b1f6f9b7fb5 100644 --- a/src/native/minipal/thread.c +++ b/src/native/minipal/thread.c @@ -1,9 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#include -#include +#if defined(__linux__) && !defined(_GNU_SOURCE) +// glibc declares pthread_setname_np only when _GNU_SOURCE is defined before . +#define _GNU_SOURCE +#endif + +#include "thread.h" #if !defined(__wasm) || defined(_REENTRANT) PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; #endif + +extern size_t minipal_get_current_thread_id_no_cache(void); +extern size_t minipal_get_current_thread_id(void); +extern int minipal_set_thread_name(pthread_t thread, const char* name); diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h index 1a22d365784d7a..db2174f3c3ad13 100644 --- a/src/native/minipal/thread.h +++ b/src/native/minipal/thread.h @@ -47,7 +47,7 @@ extern "C" { * * @return The current thread ID as a size_t value. */ -static inline size_t minipal_get_current_thread_id_no_cache(void) +inline size_t minipal_get_current_thread_id_no_cache(void) { size_t tid; #if defined(__wasm) && !defined(_REENTRANT) @@ -89,7 +89,7 @@ extern PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; * * @return The current thread ID as a size_t value. */ -static inline size_t minipal_get_current_thread_id(void) +inline size_t minipal_get_current_thread_id(void) { #if defined(__wasm) && !defined(_REENTRANT) return minipal_get_current_thread_id_no_cache(); @@ -111,7 +111,7 @@ static inline size_t minipal_get_current_thread_id(void) * @param name The desired name for the thread. * @return 0 on success, or an error code if the operation fails. */ -static inline int minipal_set_thread_name(pthread_t thread, const char* name) +inline int minipal_set_thread_name(pthread_t thread, const char* name) { #ifdef __wasm // WASM does not support pthread_setname_np yet: https://github.com/emscripten-core/emscripten/pull/18751 From 1dce0cbb5bf85c8aca62321b1661bed0c298ad2d Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Wed, 12 Aug 2026 22:25:26 +0000 Subject: [PATCH 3/6] minipal: deduplicate getexepath helper Keep minipal_getexepath inline for callers while providing one external fallback definition when the compiler does not inline it. Use a target-platform condition for the Linux auxv fallback because HAVE_GETAUXVAL is configured separately by each consumer. This ensures the inline and external definitions compile the same logic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/CMakeLists.txt | 1 + src/native/minipal/getexepath.c | 6 ++++++ src/native/minipal/getexepath.h | 13 +++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 src/native/minipal/getexepath.c diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index ce8bbd0c4035d8..54acdb84928236 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES cpufeatures.c descriptorlimit.c entrypoints.c + getexepath.c memorybarrierprocesswide.c mutex.c guid.c diff --git a/src/native/minipal/getexepath.c b/src/native/minipal/getexepath.c new file mode 100644 index 00000000000000..929142a8b7aaa9 --- /dev/null +++ b/src/native/minipal/getexepath.c @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "getexepath.h" + +extern char* minipal_getexepath(void); diff --git a/src/native/minipal/getexepath.h b/src/native/minipal/getexepath.h index 3d0c0ffdc413c2..5b89e89e50f3d6 100644 --- a/src/native/minipal/getexepath.h +++ b/src/native/minipal/getexepath.h @@ -27,7 +27,8 @@ #include #elif defined(TARGET_WASI) #include -#elif HAVE_GETAUXVAL +#elif defined(__linux__) +// Keep the inline and external definitions identical; HAVE_GETAUXVAL is configured separately by each consumer. #include #endif @@ -39,10 +40,10 @@ extern "C" { * Get the full path to the executable for the current process. * Resolves symbolic links. The caller is responsible for releasing the buffer. * - * @return A pointer to a null-terminated string containing the executable path, + * @return A pointer to a null-terminated string containing the executable path, * or NULL if an error occurs. */ -static inline char* minipal_getexepath(void) +inline char* minipal_getexepath(void) { #if defined(__APPLE__) uint32_t len = PATH_MAX; @@ -95,7 +96,7 @@ static inline char* minipal_getexepath(void) { size_t seg = strcspn(p, ":"); char path[PATH_MAX]; - + if (snprintf(path, sizeof(path), "%.*s/%s", (int)seg, p, exe) < (int)sizeof(path)) { struct stat sb; @@ -180,7 +181,7 @@ static inline char* minipal_getexepath(void) return path; } -#if HAVE_GETAUXVAL && defined(AT_EXECFN) +#if defined(AT_EXECFN) // fallback to AT_EXECFN, which does not work properly in rare cases // when .NET process is set as interpreter (shebang). const char* exePath = (const char *)(getauxval(AT_EXECFN)); @@ -188,7 +189,7 @@ static inline char* minipal_getexepath(void) { return realpath(exePath, NULL); } -#endif // HAVE_GETAUXVAL && defined(AT_EXECFN) +#endif // defined(AT_EXECFN) return NULL; #endif // defined(__APPLE__) From 670f632ef32f789fef7546541a97ee7efe4cb138 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 11 Aug 2026 00:03:13 -0400 Subject: [PATCH 4/6] minipal: deduplicate inline header helpers Keep small platform helpers inline for callers while providing one external fallback definition. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/CMakeLists.txt | 12 ++---------- src/native/minipal/cpuid.c | 18 ++++++++++++++++++ src/native/minipal/cpuid.h | 16 ++++++++++++++-- src/native/minipal/ospagesize.c | 14 +++++++++----- src/native/minipal/ospagesize.h | 4 ++-- 5 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 src/native/minipal/cpuid.c diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index 54acdb84928236..53960991f53080 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -9,6 +9,7 @@ set(SOURCES getexepath.c memorybarrierprocesswide.c mutex.c + ospagesize.c guid.c random.c debugger.c @@ -20,19 +21,10 @@ set(SOURCES log.c ) -# ospagesize is provided inline in the header on Windows and WASM; the .c file -# only contains the POSIX implementation. Including it on those platforms would -# produce a redefinition error (mono builds for wasi/browser set HOST_WASM but -# not CLR_CMAKE_TARGET_ARCH_WASM, so check both). In cross-component builds -# (e.g. host=x64, target=wasm) the code runs on the host, so we still need the -# POSIX implementation; only skip when the HOST is actually wasm. -if(NOT WIN32 AND NOT HOST_WASM AND NOT (CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CROSS_COMPONENTS_BUILD)) - list(APPEND SOURCES ospagesize.c) -endif() - if(CLR_CMAKE_HOST_UNIX) list(APPEND SOURCES cpucount.c + cpuid.c thread.c ) endif() diff --git a/src/native/minipal/cpuid.c b/src/native/minipal/cpuid.c new file mode 100644 index 00000000000000..49ad45de7e38da --- /dev/null +++ b/src/native/minipal/cpuid.c @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "cpuid.h" + +#if defined(HOST_X86) || defined(HOST_AMD64) +#if defined(HOST_UNIX) + +#if !__has_builtin(__cpuid) +extern void __cpuid(int cpuInfo[4], int function_id); +#endif + +#if !__has_builtin(__cpuidex) +extern void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id); +#endif + +#endif // HOST_UNIX +#endif // defined(HOST_X86) || defined(HOST_AMD64) diff --git a/src/native/minipal/cpuid.h b/src/native/minipal/cpuid.h index 8020775dd6df33..4e83b79fe506b1 100644 --- a/src/native/minipal/cpuid.h +++ b/src/native/minipal/cpuid.h @@ -16,13 +16,19 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + // MSVC directly defines intrinsics for __cpuid and __cpuidex matching the below signatures // We define matching signatures for use on Unix platforms. // // IMPORTANT: Unlike MSVC, Unix does not explicitly zero ECX for __cpuid #if !__has_builtin(__cpuid) -static void __cpuid(int cpuInfo[4], int function_id) +inline void __cpuid(int cpuInfo[4], int function_id) __asm("minipal_cpuid"); + +inline void __cpuid(int cpuInfo[4], int function_id) { // Based on the Clang implementation provided in cpuid.h: // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h @@ -37,7 +43,9 @@ void __cpuid(int cpuInfo[4], int function_id); #endif #if !__has_builtin(__cpuidex) -static void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id) +inline void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id) __asm("minipal_cpuidex"); + +inline void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id) { // Based on the Clang implementation provided in cpuid.h: // https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/cpuid.h @@ -51,6 +59,10 @@ static void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id) void __cpuidex(int cpuInfo[4], int function_id, int subFunction_id); #endif +#ifdef __cplusplus +} +#endif // extern "C" + #endif // HOST_UNIX #endif // defined(HOST_X86) || defined(HOST_AMD64) diff --git a/src/native/minipal/ospagesize.c b/src/native/minipal/ospagesize.c index 88e9354556fdc7..a76b80b78774b2 100644 --- a/src/native/minipal/ospagesize.c +++ b/src/native/minipal/ospagesize.c @@ -1,15 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// POSIX implementation of minipal_getpagesize. On WASM and Windows the page size -// is a compile-time constant and minipal_getpagesize is defined inline in the -// header; this file is excluded from the build on those platforms by -// src/native/minipal/CMakeLists.txt to avoid an empty translation unit. +#include "ospagesize.h" + +#if defined(HOST_WASM) || defined(HOST_WINDOWS) + +extern uint32_t minipal_getpagesize(void); + +#else #include #include #include -#include "ospagesize.h" uint32_t minipal_getpagesize(void) { @@ -38,3 +40,5 @@ uint32_t minipal_getpagesize(void) } return page_size; } + +#endif // HOST_WASM || HOST_WINDOWS diff --git a/src/native/minipal/ospagesize.h b/src/native/minipal/ospagesize.h index 0b6e0c317e2f2f..a7f31bde5d3d7f 100644 --- a/src/native/minipal/ospagesize.h +++ b/src/native/minipal/ospagesize.h @@ -19,7 +19,7 @@ extern "C" { // On other platforms the value is queried from the OS once and cached; the // definition lives in ospagesize.c so there is exactly one cache per process. #if defined(HOST_WASM) -static inline uint32_t minipal_getpagesize(void) +inline uint32_t minipal_getpagesize(void) { // WASM has no hardware pages; getpagesize() returns the 64KB memory.grow granularity, // which is too coarse for GC alignment and thresholds. Reduce the OS page size used @@ -27,7 +27,7 @@ static inline uint32_t minipal_getpagesize(void) return 16 * 1024; } #elif defined(HOST_WINDOWS) -static inline uint32_t minipal_getpagesize(void) +inline uint32_t minipal_getpagesize(void) { // The page size on Windows is 4KB and is not going to change. return 4 * 1024; From 693e79eaa0f1e103c58cc2bcf7ca5f7e11d4ce68 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 13 Aug 2026 15:31:44 +0000 Subject: [PATCH 5/6] minipal: move non-critical helpers out of line Move executable path resolution, uncached thread ID lookup, and thread naming into their source files. Keep only the cached thread ID fast path inline, and configure getauxval availability directly for minipal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/configure.cmake | 1 + src/native/minipal/getexepath.c | 179 ++++++++++++++++++++++++- src/native/minipal/getexepath.h | 180 +------------------------- src/native/minipal/minipalconfig.h.in | 1 + src/native/minipal/thread.c | 97 +++++++++++++- src/native/minipal/thread.h | 96 +------------- 6 files changed, 279 insertions(+), 275 deletions(-) diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index 75ab81d852a339..00be7c33163c69 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -12,6 +12,7 @@ check_function_exists(fsync HAVE_FSYNC) check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO) check_symbol_exists(arc4random_buf "stdlib.h" HAVE_ARC4RANDOM_BUF) +check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL) check_symbol_exists(getrandom "sys/random.h" HAVE_GETRANDOM) check_symbol_exists(getentropy "unistd.h" HAVE_GETENTROPY) check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC) diff --git a/src/native/minipal/getexepath.c b/src/native/minipal/getexepath.c index 929142a8b7aaa9..dfc32aafcccd70 100644 --- a/src/native/minipal/getexepath.c +++ b/src/native/minipal/getexepath.c @@ -1,6 +1,183 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#include "minipalconfig.h" #include "getexepath.h" -extern char* minipal_getexepath(void); +#include +#include +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#elif defined(__FreeBSD__) +#include +#include +#include +#elif defined(__OpenBSD__) +#include +#include +#include +#elif defined(_WIN32) +#include +#elif defined(__HAIKU__) +#include +#include +#elif HAVE_GETAUXVAL +#include +#endif + +char* minipal_getexepath(void) +{ +#if defined(__APPLE__) + uint32_t len = PATH_MAX; + char pathBuf[PATH_MAX]; + if (_NSGetExecutablePath(pathBuf, &len) != 0) + { + errno = EINVAL; + return NULL; + } + + return realpath(pathBuf, NULL); +#elif defined(__FreeBSD__) + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + char path[PATH_MAX]; + size_t len = sizeof(path); + if (sysctl(name, 4, path, &len, NULL, 0) != 0) + { + return NULL; + } + + return strdup(path); +#elif defined(__OpenBSD__) + const int name[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; + size_t len = 0; + if (sysctl(name, 4, NULL, &len, NULL, 0) != 0 || len == 0) + { + return NULL; + } + + char *buf = (char *)malloc(len); + if (buf == NULL) + { + return NULL; + } + + if (sysctl(name, 4, buf, &len, NULL, 0) != 0) + { + free(buf); + return NULL; + } + + // Cast the start of the buffer to access the char * layout safely + char **argv = (char **)buf; + const char *exe = argv[0]; + + if (strchr(exe, '/') == NULL) + { + const char *p = getenv("PATH"); + while (p != NULL && *p != '\0') + { + size_t seg = strcspn(p, ":"); + char path[PATH_MAX]; + + if (snprintf(path, sizeof(path), "%.*s/%s", (int)seg, p, exe) < (int)sizeof(path)) + { + struct stat sb; + if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) + { + char *resolved = realpath(path, NULL); + free(buf); + return resolved; + } + } + + p += seg; + if (*p == ':') + p++; + } + } + + char *resolved = realpath(exe, NULL); + free(buf); + return resolved; +#elif defined(__sun) + const char* path = getexecname(); + if (path == NULL) + { + return NULL; + } + + return realpath(path, NULL); +#elif defined(__HAIKU__) + char path[B_PATH_NAME_LENGTH]; + status_t status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, path, B_PATH_NAME_LENGTH); + if (status != B_OK) + { + errno = status; + return NULL; + } + + return realpath(path, NULL); +#elif defined(_WIN32) + char path[MAX_PATH]; + if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0) + { + return NULL; + } + + return strdup(path); +#elif defined(TARGET_BROWSER) + const char *browserVirtualAppBase = "/"; // keep in sync other places that define browserVirtualAppBase + return strdup(browserVirtualAppBase); +#elif defined(TARGET_WASI) + // WASI has no /proc, no AT_EXECFN, and argv[0] is unreliable (often "/"). + // corerun.wasm is launched with the CORE_ROOT env var set to the directory + // that holds CoreCLR (System.Private.CoreLib.dll and friends). The PAL only + // needs a path whose dirname is that directory, so synthesize one here. + const char* coreRoot = getenv("CORE_ROOT"); + if (coreRoot == NULL || coreRoot[0] == '\0') + { + return strdup("/"); + } + size_t coreRootLen = strlen(coreRoot); + const char* suffix = "/corerun"; + size_t suffixLen = strlen(suffix); + char* result = (char*)malloc(coreRootLen + suffixLen + 1); + if (result == NULL) + { + return NULL; + } + memcpy(result, coreRoot, coreRootLen); + memcpy(result + coreRootLen, suffix, suffixLen + 1); + return result; +#else +#ifdef __linux__ + const char* symlinkEntrypointExecutable = "/proc/self/exe"; +#else + const char* symlinkEntrypointExecutable = "/proc/curproc/exe"; +#endif + + // Resolve the symlink to the executable from /proc + char* path = realpath(symlinkEntrypointExecutable, NULL); + if (path) + { + return path; + } + +#if HAVE_GETAUXVAL && defined(AT_EXECFN) + // fallback to AT_EXECFN, which does not work properly in rare cases + // when .NET process is set as interpreter (shebang). + const char* exePath = (const char *)(getauxval(AT_EXECFN)); + if (exePath) + { + return realpath(exePath, NULL); + } +#endif // HAVE_GETAUXVAL && defined(AT_EXECFN) + + return NULL; +#endif // defined(__APPLE__) +} diff --git a/src/native/minipal/getexepath.h b/src/native/minipal/getexepath.h index 5b89e89e50f3d6..da35e02a981586 100644 --- a/src/native/minipal/getexepath.h +++ b/src/native/minipal/getexepath.h @@ -4,34 +4,6 @@ #ifndef HAVE_MINIPAL_GETEXEPATH_H #define HAVE_MINIPAL_GETEXEPATH_H -#include -#include -#include - -#if defined(__APPLE__) -#include -#elif defined(__FreeBSD__) -#include -#include -#include -#include -#elif defined(__OpenBSD__) -#include -#include -#include -#include -#elif defined(_WIN32) -#include -#elif defined(__HAIKU__) -#include -#include -#elif defined(TARGET_WASI) -#include -#elif defined(__linux__) -// Keep the inline and external definitions identical; HAVE_GETAUXVAL is configured separately by each consumer. -#include -#endif - #ifdef __cplusplus extern "C" { #endif @@ -43,157 +15,7 @@ extern "C" { * @return A pointer to a null-terminated string containing the executable path, * or NULL if an error occurs. */ -inline char* minipal_getexepath(void) -{ -#if defined(__APPLE__) - uint32_t len = PATH_MAX; - char pathBuf[PATH_MAX]; - if (_NSGetExecutablePath(pathBuf, &len) != 0) - { - errno = EINVAL; - return NULL; - } - - return realpath(pathBuf, NULL); -#elif defined(__FreeBSD__) - static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - char path[PATH_MAX]; - size_t len = sizeof(path); - if (sysctl(name, 4, path, &len, NULL, 0) != 0) - { - return NULL; - } - - return strdup(path); -#elif defined(__OpenBSD__) - const int name[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; - size_t len = 0; - if (sysctl(name, 4, NULL, &len, NULL, 0) != 0 || len == 0) - { - return NULL; - } - - char *buf = (char *)malloc(len); - if (buf == NULL) - { - return NULL; - } - - if (sysctl(name, 4, buf, &len, NULL, 0) != 0) - { - free(buf); - return NULL; - } - - // Cast the start of the buffer to access the char * layout safely - char **argv = (char **)buf; - const char *exe = argv[0]; - - if (strchr(exe, '/') == NULL) - { - const char *p = getenv("PATH"); - while (p != NULL && *p != '\0') - { - size_t seg = strcspn(p, ":"); - char path[PATH_MAX]; - - if (snprintf(path, sizeof(path), "%.*s/%s", (int)seg, p, exe) < (int)sizeof(path)) - { - struct stat sb; - if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) - { - char *resolved = realpath(path, NULL); - free(buf); - return resolved; - } - } - - p += seg; - if (*p == ':') - p++; - } - } - - char *resolved = realpath(exe, NULL); - free(buf); - return resolved; -#elif defined(__sun) - const char* path = getexecname(); - if (path == NULL) - { - return NULL; - } - - return realpath(path, NULL); -#elif defined(__HAIKU__) - char path[B_PATH_NAME_LENGTH]; - status_t status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, path, B_PATH_NAME_LENGTH); - if (status != B_OK) - { - errno = status; - return NULL; - } - - return realpath(path, NULL); -#elif defined(_WIN32) - char path[MAX_PATH]; - if (GetModuleFileNameA(NULL, path, MAX_PATH) == 0) - { - return NULL; - } - - return strdup(path); -#elif defined(TARGET_BROWSER) - const char *browserVirtualAppBase = "/"; // keep in sync other places that define browserVirtualAppBase - return strdup(browserVirtualAppBase); -#elif defined(TARGET_WASI) - // WASI has no /proc, no AT_EXECFN, and argv[0] is unreliable (often "/"). - // corerun.wasm is launched with the CORE_ROOT env var set to the directory - // that holds CoreCLR (System.Private.CoreLib.dll and friends). The PAL only - // needs a path whose dirname is that directory, so synthesize one here. - const char* coreRoot = getenv("CORE_ROOT"); - if (coreRoot == NULL || coreRoot[0] == '\0') - { - return strdup("/"); - } - size_t coreRootLen = strlen(coreRoot); - const char* suffix = "/corerun"; - size_t suffixLen = strlen(suffix); - char* result = (char*)malloc(coreRootLen + suffixLen + 1); - if (result == NULL) - { - return NULL; - } - memcpy(result, coreRoot, coreRootLen); - memcpy(result + coreRootLen, suffix, suffixLen + 1); - return result; -#else -#ifdef __linux__ - const char* symlinkEntrypointExecutable = "/proc/self/exe"; -#else - const char* symlinkEntrypointExecutable = "/proc/curproc/exe"; -#endif - - // Resolve the symlink to the executable from /proc - char* path = realpath(symlinkEntrypointExecutable, NULL); - if (path) - { - return path; - } - -#if defined(AT_EXECFN) - // fallback to AT_EXECFN, which does not work properly in rare cases - // when .NET process is set as interpreter (shebang). - const char* exePath = (const char *)(getauxval(AT_EXECFN)); - if (exePath) - { - return realpath(exePath, NULL); - } -#endif // defined(AT_EXECFN) - - return NULL; -#endif // defined(__APPLE__) -} +char* minipal_getexepath(void); #ifdef __cplusplus } diff --git a/src/native/minipal/minipalconfig.h.in b/src/native/minipal/minipalconfig.h.in index 938eb42c415187..f78a66a7fcd852 100644 --- a/src/native/minipal/minipalconfig.h.in +++ b/src/native/minipal/minipalconfig.h.in @@ -4,6 +4,7 @@ #cmakedefine01 HAVE_ARC4RANDOM_BUF #cmakedefine01 HAVE_GETRANDOM #cmakedefine01 HAVE_GETENTROPY +#cmakedefine01 HAVE_GETAUXVAL #cmakedefine01 HAVE_AUXV_HWCAP_H #cmakedefine01 HAVE_HWPROBE_H #cmakedefine01 HAVE_RESOURCE_H diff --git a/src/native/minipal/thread.c b/src/native/minipal/thread.c index 0d1b1f6f9b7fb5..cc527a4ca1c522 100644 --- a/src/native/minipal/thread.c +++ b/src/native/minipal/thread.c @@ -8,10 +8,103 @@ #include "thread.h" +#include +#include +#include + +#if defined(__linux__) +#include +#include +#elif defined(__FreeBSD__) +#include +#elif defined(__OpenBSD__) +#include +#include +#elif defined(__NetBSD__) +#include +#elif defined(__HAIKU__) +#include +#endif + +#ifdef PTHREAD_MAX_NAMELEN_NP +#define MINIPAL_MAX_THREAD_NAME_LENGTH (PTHREAD_MAX_NAMELEN_NP - 1) +#elif defined(__APPLE__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH 63 +#elif defined(__FreeBSD__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH MAXCOMLEN +#elif defined(__HAIKU__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH (B_OS_NAME_LENGTH - 1) +#else +#define MINIPAL_MAX_THREAD_NAME_LENGTH 15 +#endif + #if !defined(__wasm) || defined(_REENTRANT) PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; #endif -extern size_t minipal_get_current_thread_id_no_cache(void); +size_t minipal_get_current_thread_id_no_cache(void) +{ + size_t tid; +#if defined(__wasm) && !defined(_REENTRANT) + tid = 1; // In non-reentrant WASM builds, we define a single thread with ID 1. +#else // !__wasm || _REENTRANT + +#if defined(__linux__) + tid = (size_t)syscall(SYS_gettid); +#elif defined(__APPLE__) + uint64_t thread_id; + pthread_threadid_np(pthread_self(), &thread_id); + tid = (size_t)thread_id; // Cast the uint64_t thread ID to size_t +#elif defined(__FreeBSD__) + tid = (size_t)pthread_getthreadid_np(); +#elif defined(__NetBSD__) + tid = (size_t)_lwp_self(); +#elif defined(__OpenBSD__) + tid = (size_t)getthrid(); +#elif defined(__HAIKU__) + tid = (size_t)find_thread(NULL); +#elif defined(__sun) + tid = (size_t)pthread_self(); +#elif defined(__wasm) + tid = (size_t)(void*)pthread_self(); +#else +#error "Unsupported platform" +#endif + +#endif // __wasm && !_REENTRANT + return tid; +} + extern size_t minipal_get_current_thread_id(void); -extern int minipal_set_thread_name(pthread_t thread, const char* name); + +int minipal_set_thread_name(pthread_t thread, const char* name) +{ +#ifdef __wasm + // WASM does not support pthread_setname_np yet: https://github.com/emscripten-core/emscripten/pull/18751 + return 0; +#else + const char* threadName = name; + char truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH + 1]; + + if (strlen(name) > MINIPAL_MAX_THREAD_NAME_LENGTH) + { + strncpy(truncatedName, name, MINIPAL_MAX_THREAD_NAME_LENGTH); + truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH] = '\0'; + threadName = truncatedName; + } + +#if defined(__APPLE__) + // On Apple OSes, pthread_setname_np only works for the calling thread. + if (thread != pthread_self()) return 0; + + return pthread_setname_np(threadName); +#elif defined(__OpenBSD__) + pthread_set_name_np(thread, threadName); + return 0; +#elif defined(__HAIKU__) + return rename_thread(get_pthread_thread_id(thread), threadName); +#else + return pthread_setname_np(thread, threadName); +#endif +#endif +} diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h index db2174f3c3ad13..10a1f22683e4fe 100644 --- a/src/native/minipal/thread.h +++ b/src/native/minipal/thread.h @@ -6,38 +6,10 @@ #ifndef HOST_WINDOWS +#include #include -#include -#include -#include #include -#if defined(__linux__) -#include -#include -#elif defined(__FreeBSD__) -#include -#elif defined(__OpenBSD__) -#include -#include -#elif defined(__NetBSD__) -#include -#elif defined(__HAIKU__) -#include -#endif - -#ifdef PTHREAD_MAX_NAMELEN_NP -#define MINIPAL_MAX_THREAD_NAME_LENGTH (PTHREAD_MAX_NAMELEN_NP - 1) -#elif defined(__APPLE__) -#define MINIPAL_MAX_THREAD_NAME_LENGTH 63 -#elif defined(__FreeBSD__) -#define MINIPAL_MAX_THREAD_NAME_LENGTH MAXCOMLEN -#elif defined(__HAIKU__) -#define MINIPAL_MAX_THREAD_NAME_LENGTH (B_OS_NAME_LENGTH - 1) -#else -#define MINIPAL_MAX_THREAD_NAME_LENGTH 15 -#endif - #ifdef __cplusplus extern "C" { #endif @@ -47,38 +19,7 @@ extern "C" { * * @return The current thread ID as a size_t value. */ -inline size_t minipal_get_current_thread_id_no_cache(void) -{ - size_t tid; -#if defined(__wasm) && !defined(_REENTRANT) - tid = 1; // In non-reentrant WASM builds, we define a single thread with ID 1. -#else // !__wasm || _REENTRANT - -#if defined(__linux__) - tid = (size_t)syscall(SYS_gettid); -#elif defined(__APPLE__) - uint64_t thread_id; - pthread_threadid_np(pthread_self(), &thread_id); - tid = (size_t)thread_id; // Cast the uint64_t thread ID to size_t -#elif defined(__FreeBSD__) - tid = (size_t)pthread_getthreadid_np(); -#elif defined(__NetBSD__) - tid = (size_t)_lwp_self(); -#elif defined(__OpenBSD__) - tid = (size_t)getthrid(); -#elif defined(__HAIKU__) - tid = (size_t)find_thread(NULL); -#elif defined(__sun) - tid = (size_t)pthread_self(); -#elif defined(__wasm) - tid = (size_t)(void*)pthread_self(); -#else -#error "Unsupported platform" -#endif - -#endif // __wasm && !_REENTRANT - return tid; -} +size_t minipal_get_current_thread_id_no_cache(void); #if !defined(__wasm) || defined(_REENTRANT) extern PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; @@ -111,38 +52,7 @@ inline size_t minipal_get_current_thread_id(void) * @param name The desired name for the thread. * @return 0 on success, or an error code if the operation fails. */ -inline int minipal_set_thread_name(pthread_t thread, const char* name) -{ -#ifdef __wasm - // WASM does not support pthread_setname_np yet: https://github.com/emscripten-core/emscripten/pull/18751 - return 0; -#else - const char* threadName = name; - char truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH + 1]; - - if (strlen(name) > MINIPAL_MAX_THREAD_NAME_LENGTH) - { - strncpy(truncatedName, name, MINIPAL_MAX_THREAD_NAME_LENGTH); - truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH] = '\0'; - threadName = truncatedName; - } - -#if defined(__APPLE__) - // On Apple OSes, pthread_setname_np only works for the calling thread. - if (thread != pthread_self()) return 0; - - return pthread_setname_np(threadName); -#elif defined(__OpenBSD__) - pthread_set_name_np(thread, threadName); - return 0; -#elif defined(__HAIKU__) - return rename_thread(get_pthread_thread_id(thread), threadName); -#else - return pthread_setname_np(thread, threadName); -#endif -#endif -} - +int minipal_set_thread_name(pthread_t thread, const char* name); #ifdef __cplusplus } From 2a23ac828056dd04ca005c7585e4a3f6c81eecd3 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 13 Aug 2026 20:25:46 +0000 Subject: [PATCH 6/6] minipal: use Windows strdup name Use the MSVC-supported _strdup spelling in the Windows executable-path implementation to avoid C4996 when getexepath.c is compiled as part of minipal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/getexepath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/minipal/getexepath.c b/src/native/minipal/getexepath.c index dfc32aafcccd70..40785b0d7e0439 100644 --- a/src/native/minipal/getexepath.c +++ b/src/native/minipal/getexepath.c @@ -129,7 +129,7 @@ char* minipal_getexepath(void) return NULL; } - return strdup(path); + return _strdup(path); #elif defined(TARGET_BROWSER) const char *browserVirtualAppBase = "/"; // keep in sync other places that define browserVirtualAppBase return strdup(browserVirtualAppBase);