From 20f7cf42e294751e178362a9bac2495bd5329b45 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 16 Sep 2026 21:12:44 +0900 Subject: [PATCH 1/3] Count processors across all processor groups in Etc.nprocessors GetSystemInfo() reports the logical processors of the current processor group only, so Etc.nprocessors returned at most 64 on Windows machines with more than 64 logical processors. GetActiveProcessorCount(ALL_PROCESSOR_GROUPS) counts every group. It is looked up at runtime because mingw-w64 declares it only for _WIN32_WINNT >= 0x0601 while the mingw build targets 0x0600. Co-Authored-By: Claude Fable 5.1 --- ext/etc/etc.c | 19 ++++++++++++++++--- test/etc/test_etc.rb | 3 +++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ext/etc/etc.c b/ext/etc/etc.c index 627dc92..a1b726b 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -1074,6 +1074,7 @@ etc_nprocessors_affin(void) * This method is implemented using: * - sched_getaffinity(): Linux * - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX + * - GetActiveProcessorCount(ALL_PROCESSOR_GROUPS): Windows * * *Example:* * @@ -1112,9 +1113,21 @@ etc_nprocessors(VALUE obj) rb_sys_fail("sysconf(_SC_NPROCESSORS_ONLN)"); } #else - SYSTEM_INFO si; - GetSystemInfo(&si); - ret = (long)si.dwNumberOfProcessors; + /* GetSystemInfo() counts the current processor group only, and GetActiveProcessorCount() is declared only for Windows 7 or later */ + typedef DWORD (WINAPI *GetActiveProcessorCount_t)(WORD); + GetActiveProcessorCount_t pGetActiveProcessorCount = + (GetActiveProcessorCount_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetActiveProcessorCount"); + DWORD n = 0; + + if (pGetActiveProcessorCount) { + n = pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS); + } + if (n == 0) { + SYSTEM_INFO si; + GetSystemInfo(&si); + n = si.dwNumberOfProcessors; + } + ret = (long)n; #endif return LONG2NUM(ret); } diff --git a/test/etc/test_etc.rb b/test/etc/test_etc.rb index c2e3af6..611832e 100644 --- a/test/etc/test_etc.rb +++ b/test/etc/test_etc.rb @@ -167,6 +167,9 @@ def test_pathconf def test_nprocessors n = Etc.nprocessors assert_operator(1, :<=, n) + if /mswin|mingw/ =~ RUBY_PLATFORM + assert_operator(ENV["NUMBER_OF_PROCESSORS"].to_i, :<=, n) + end end def test_sysconfdir From 77a035fcaaadb4592b844f81120ca268b5ce2748 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 16 Sep 2026 21:21:07 +0900 Subject: [PATCH 2/3] Define ALL_PROCESSOR_GROUPS for mingw builds mingw-w64 guards the macro with _WIN32_WINNT >= 0x0601 as well as the function, while the mingw build targets 0x0600. Co-Authored-By: Claude Fable 5.1 --- ext/etc/etc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/etc/etc.c b/ext/etc/etc.c index a1b726b..7155c88 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -1113,7 +1113,10 @@ etc_nprocessors(VALUE obj) rb_sys_fail("sysconf(_SC_NPROCESSORS_ONLN)"); } #else - /* GetSystemInfo() counts the current processor group only, and GetActiveProcessorCount() is declared only for Windows 7 or later */ +# ifndef ALL_PROCESSOR_GROUPS +# define ALL_PROCESSOR_GROUPS 0xffff +# endif + /* GetSystemInfo() counts the current processor group only, and mingw-w64 declares GetActiveProcessorCount() only for _WIN32_WINNT >= 0x0601 */ typedef DWORD (WINAPI *GetActiveProcessorCount_t)(WORD); GetActiveProcessorCount_t pGetActiveProcessorCount = (GetActiveProcessorCount_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetActiveProcessorCount"); From a3cfa2075c1f7ff83ff7c4576c93c66cb67c8572 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 16 Sep 2026 21:21:08 +0900 Subject: [PATCH 3/3] Require NUMBER_OF_PROCESSORS in test_nprocessors A missing variable turned the lower bound into 0, which the existing assertion already covers. Co-Authored-By: Claude Fable 5.1 --- test/etc/test_etc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/etc/test_etc.rb b/test/etc/test_etc.rb index 611832e..d0e19f3 100644 --- a/test/etc/test_etc.rb +++ b/test/etc/test_etc.rb @@ -168,7 +168,7 @@ def test_nprocessors n = Etc.nprocessors assert_operator(1, :<=, n) if /mswin|mingw/ =~ RUBY_PLATFORM - assert_operator(ENV["NUMBER_OF_PROCESSORS"].to_i, :<=, n) + assert_operator(Integer(ENV.fetch("NUMBER_OF_PROCESSORS")), :<=, n) end end