From 08ad3840f954ef215adf98fccf42d178e6f0545d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 14:37:15 +0200 Subject: [PATCH 1/3] Increase file descriptor limit in native AOT executables Fixes #82719 --- src/coreclr/nativeaot/Bootstrap/main.cpp | 3 ++ src/coreclr/pal/src/CMakeLists.txt | 2 - src/coreclr/pal/src/init/pal.cpp | 51 +----------------------- src/mono/CMakeLists.txt | 2 - src/mono/mono/mini/driver.c | 28 ++----------- src/native/minipal/CMakeLists.txt | 7 ++++ src/native/minipal/configure.cmake | 1 + src/native/minipal/descriptorlimit.c | 41 +++++++++++++++++++ src/native/minipal/descriptorlimit.h | 20 ++++++++++ src/native/minipal/minipalconfig.h.in | 1 + 10 files changed, 78 insertions(+), 78 deletions(-) create mode 100644 src/native/minipal/descriptorlimit.c create mode 100644 src/native/minipal/descriptorlimit.h diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 57eb0012666e1b..8e98bc463d33c8 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include +#include #if defined(DEBUG) && defined(_WIN32) #include @@ -223,6 +224,8 @@ int main(int argc, char* argv[]) if (initval != 0) return initval; + minipal_increase_descriptor_limit(); + #if defined(DEBUG) && defined(_WIN32) // work around Debug UCRT shutdown issues: https://github.com/dotnet/runtime/issues/108640 int exitCode = __managed__Main(argc, argv); diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index a850607a20c359..1395013eb59601 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -101,8 +101,6 @@ if(CLR_CMAKE_HOST_ARCH_ARM64 AND CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET endif(CLR_CMAKE_HOST_ARCH_ARM64 AND CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_LINUX_MUSL) if(CLR_CMAKE_TARGET_LINUX_MUSL) - # Setting RLIMIT_NOFILE breaks debugging of coreclr on Alpine Linux for some reason - add_definitions(-DDONT_SET_RLIMIT_NOFILE) # On Alpine Linux, we need to ensure that the reported stack range for the primary thread is # larger than the initial committed stack size. add_definitions(-DENSURE_PRIMARY_STACK_SIZE) diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 4d02460f16d51a..ea24c25d6e5252 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -37,6 +37,7 @@ SET_DEFAULT_DEBUG_CHANNEL(PAL); // some headers have code with asserts, so do th #include "pal/cgroup.h" #include #include +#include #if HAVE_MACH_EXCEPTIONS #include "../exception/machexception.h" @@ -48,7 +49,6 @@ SET_DEFAULT_DEBUG_CHANNEL(PAL); // some headers have code with asserts, so do th #include #include #include -#include #include #include #include @@ -116,7 +116,6 @@ static minipal_mutex* init_critsec = NULL; static DWORD g_initializeDLLFlags = PAL_INITIALIZE_DLL; static int Initialize(int argc, const char *const argv[], DWORD flags); -static BOOL INIT_IncreaseDescriptorLimit(void); static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv); static LPWSTR INIT_GetCurrentEXEPath(); static BOOL INIT_SharedFilesPath(void); @@ -401,7 +400,7 @@ Initialize( goto CLEANUP1; } - if (!INIT_IncreaseDescriptorLimit()) + if (!minipal_increase_descriptor_limit()) { ERROR("Unable to increase the file descriptor limit!\n"); // We can continue if this fails; we'll just have problems if @@ -906,52 +905,6 @@ void PALInitUnlock(void) /* Internal functions *********************************************************/ -/*++ -Function: - INIT_IncreaseDescriptorLimit [internal] - -Abstract: - Calls setrlimit(2) to increase the maximum number of file descriptors - this process can open. - -Return value: - TRUE if the call to setrlimit succeeded; FALSE otherwise. ---*/ -static BOOL INIT_IncreaseDescriptorLimit(void) -{ -#ifdef TARGET_WASM - // WebAssembly cannot set limits - return TRUE; -#endif -#ifndef DONT_SET_RLIMIT_NOFILE - struct rlimit rlp; - int result; - - result = getrlimit(RLIMIT_NOFILE, &rlp); - if (result != 0) - { - return FALSE; - } - // Set our soft limit for file descriptors to be the same - // as the max limit. - rlp.rlim_cur = rlp.rlim_max; -#ifdef __APPLE__ - // Based on compatibility note in setrlimit(2) manpage for OSX, - // trim the limit to OPEN_MAX. - if (rlp.rlim_cur > OPEN_MAX) - { - rlp.rlim_cur = OPEN_MAX; - } -#endif - result = setrlimit(RLIMIT_NOFILE, &rlp); - if (result != 0) - { - return FALSE; - } -#endif // !DONT_SET_RLIMIT_NOFILE - return TRUE; -} - /*++ Function: INIT_FormatCommandLine [Internal] diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 834c4881aac512..b5dc8acebadc7a 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -857,8 +857,6 @@ set(FULL_VERSION ${product_version_string}) ###################################### if(CLR_CMAKE_TARGET_LINUX_MUSL) - # Setting RLIMIT_NOFILE breaks debugging of coreclr on musl-libc for some reason - add_definitions(-DDONT_SET_RLIMIT_NOFILE) # On musl-libc, we need to ensure that the reported stack range for the primary thread is # larger than the initial committed stack size. add_definitions(-DENSURE_PRIMARY_STACK_SIZE) diff --git a/src/mono/mono/mini/driver.c b/src/mono/mono/mini/driver.c index 0e9b4f833e8225..05e8a0a05fe591 100644 --- a/src/mono/mono/mini/driver.c +++ b/src/mono/mono/mini/driver.c @@ -54,6 +54,8 @@ #include #include +#include + #include "mini.h" #include #include "aot-compiler.h" @@ -68,9 +70,6 @@ #include #include #include -#ifdef HAVE_SYS_RESOURCE_H -# include -#endif static FILE *mini_stats_fd; @@ -1876,27 +1875,6 @@ mono_set_use_smp (int use_smp) #endif } -static void -increase_descriptor_limit (void) -{ -#if defined(HAVE_GETRLIMIT) && !defined(DONT_SET_RLIMIT_NOFILE) - struct rlimit limit; - - if (getrlimit (RLIMIT_NOFILE, &limit) == 0) { - // Set our soft limit for file descriptors to be the same - // as the max limit. - limit.rlim_cur = limit.rlim_max; -#ifdef __APPLE__ - // Based on compatibility note in setrlimit(2) manpage for OSX, - // trim the limit to OPEN_MAX. - if (limit.rlim_cur > OPEN_MAX) - limit.rlim_cur = OPEN_MAX; -#endif - setrlimit (RLIMIT_NOFILE, &limit); - } -#endif -} - #define MONO_HANDLERS_ARGUMENT "--handlers=" #define MONO_HANDLERS_ARGUMENT_LEN STRING_LENGTH(MONO_HANDLERS_ARGUMENT) @@ -2024,7 +2002,7 @@ mono_main (int argc, char* argv[]) setlocale (LC_ALL, ""); - increase_descriptor_limit (); + minipal_increase_descriptor_limit (); if (g_hasenv ("MONO_NO_SMP")) mono_set_use_smp (FALSE); diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index f32281a56bb365..85d8bc7fc2cfce 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -2,6 +2,7 @@ include(configure.cmake) set(SOURCES cpufeatures.c + descriptorlimit.c memorybarrierprocesswide.c mutex.c guid.c @@ -15,6 +16,12 @@ set(SOURCES log.c ) +# Setting RLIMIT_NOFILE breaks debugging of coreclr on Alpine Linux for some reason +# Setting limits in Browser/WASI doesn't make sense +if(CLR_CMAKE_TARGET_LINUX_MUSL OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) + add_definitions(-DDONT_SET_RLIMIT_NOFILE) +endif() + # Provide an object library for scenarios where we ship static libraries include_directories(${CLR_SRC_NATIVE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index 473c4f8124c521..27c8e803c26f5c 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -5,6 +5,7 @@ include(CheckSymbolExists) check_include_files("windows.h;bcrypt.h" HAVE_BCRYPT_H) check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H) check_include_files("asm/hwprobe.h" HAVE_HWPROBE_H) +check_include_files("sys/resource.h" HAVE_RESOURCE_H) check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME) check_function_exists(fsync HAVE_FSYNC) diff --git a/src/native/minipal/descriptorlimit.c b/src/native/minipal/descriptorlimit.c new file mode 100644 index 00000000000000..e08bcc17ca049c --- /dev/null +++ b/src/native/minipal/descriptorlimit.c @@ -0,0 +1,41 @@ +// 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" + +#if HAVE_RESOURCE_H +#include +#endif + +#include "descriptorlimit.h" + +bool minipal_increase_descriptor_limit(void) +{ +#if HAVE_RESOURCE_H && !defined(DONT_SET_RLIMIT_NOFILE) + struct rlimit rlp; + int result; + + result = getrlimit(RLIMIT_NOFILE, &rlp); + if (result != 0) + { + return false; + } + // Set our soft limit for file descriptors to be the same + // as the max limit. + rlp.rlim_cur = rlp.rlim_max; +#ifdef __APPLE__ + // Based on compatibility note in setrlimit(2) manpage for OSX, + // trim the limit to OPEN_MAX. + if (rlp.rlim_cur > OPEN_MAX) + { + rlp.rlim_cur = OPEN_MAX; + } +#endif + result = setrlimit(RLIMIT_NOFILE, &rlp); + if (result != 0) + { + return false; + } +#endif // HAVE_RESOURCE_H && !DONT_SET_RLIMIT_NOFILE + return true; +} diff --git a/src/native/minipal/descriptorlimit.h b/src/native/minipal/descriptorlimit.h new file mode 100644 index 00000000000000..0656284585a466 --- /dev/null +++ b/src/native/minipal/descriptorlimit.h @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef HAVE_MINIPAL_DESCRIPTORLIMIT_H +#define HAVE_MINIPAL_DESCRIPTORLIMIT_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +bool minipal_increase_descriptor_limit(void); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // HAVE_MINIPAL_DESCRIPTORLIMIT_H diff --git a/src/native/minipal/minipalconfig.h.in b/src/native/minipal/minipalconfig.h.in index 1ecd683be425c2..d9d36129597249 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_AUXV_HWCAP_H #cmakedefine01 HAVE_HWPROBE_H +#cmakedefine01 HAVE_RESOURCE_H #cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_SYSCTLBYNAME #cmakedefine01 HAVE_CLOCK_MONOTONIC From 2e101bfaaeac1b94f77dcffa15728dad55271b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 06:01:01 -0700 Subject: [PATCH 2/3] Apple platform fix guess --- src/native/minipal/descriptorlimit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/native/minipal/descriptorlimit.c b/src/native/minipal/descriptorlimit.c index e08bcc17ca049c..61a64b7c8e8405 100644 --- a/src/native/minipal/descriptorlimit.c +++ b/src/native/minipal/descriptorlimit.c @@ -7,6 +7,8 @@ #include #endif +#include + #include "descriptorlimit.h" bool minipal_increase_descriptor_limit(void) From 02f1b58347c83e12fec1ff175538683369b8fc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 22:59:34 +0200 Subject: [PATCH 3/3] Apply suggestions from code review --- src/native/minipal/CMakeLists.txt | 6 ------ src/native/minipal/descriptorlimit.c | 8 ++++++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index 85d8bc7fc2cfce..4d4019678a845c 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -16,12 +16,6 @@ set(SOURCES log.c ) -# Setting RLIMIT_NOFILE breaks debugging of coreclr on Alpine Linux for some reason -# Setting limits in Browser/WASI doesn't make sense -if(CLR_CMAKE_TARGET_LINUX_MUSL OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI) - add_definitions(-DDONT_SET_RLIMIT_NOFILE) -endif() - # Provide an object library for scenarios where we ship static libraries include_directories(${CLR_SRC_NATIVE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/native/minipal/descriptorlimit.c b/src/native/minipal/descriptorlimit.c index 61a64b7c8e8405..b1550fdc8f74e3 100644 --- a/src/native/minipal/descriptorlimit.c +++ b/src/native/minipal/descriptorlimit.c @@ -13,7 +13,11 @@ bool minipal_increase_descriptor_limit(void) { -#if HAVE_RESOURCE_H && !defined(DONT_SET_RLIMIT_NOFILE) +#if TARGET_WASM + // WebAssembly cannot set limits +#elif TARGET_LINUX_MUSL + // Setting RLIMIT_NOFILE breaks debugging of coreclr on Alpine Linux for some reason +#elif HAVE_RESOURCE_H struct rlimit rlp; int result; @@ -38,6 +42,6 @@ bool minipal_increase_descriptor_limit(void) { return false; } -#endif // HAVE_RESOURCE_H && !DONT_SET_RLIMIT_NOFILE +#endif return true; }