diff options
Diffstat (limited to 'src/tools/mhd_tool_get_cpu_count.c')
-rw-r--r-- | src/tools/mhd_tool_get_cpu_count.c | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/src/tools/mhd_tool_get_cpu_count.c b/src/tools/mhd_tool_get_cpu_count.c new file mode 100644 index 00000000..81badf28 --- /dev/null +++ b/src/tools/mhd_tool_get_cpu_count.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | This file is part of GNU libmicrohttpd | ||
3 | Copyright (C) 2023 Evgeny Grin (Karlson2k) | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file tools/mhd_tool_get_cpu_count.c | ||
22 | * @brief Implementation of functions to detect the number of available | ||
23 | * CPU cores. | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | ||
26 | |||
27 | #include "mhd_options.h" | ||
28 | #include "mhd_tool_get_cpu_count.h" | ||
29 | #ifdef HAVE_SYS_TYPES_H | ||
30 | # include <sys/types.h> | ||
31 | #endif /* HAVE_SYS_TYPES_H */ | ||
32 | #ifdef HAVE_SYS_PARAM_H | ||
33 | # include <sys/param.h> | ||
34 | #endif /* HAVE_SYS_PARAM_H */ | ||
35 | #ifdef HAVE_SYS__CPUSET_H | ||
36 | # include <sys/_cpuset.h> | ||
37 | #endif /* HAVE_SYS_PARAM_H */ | ||
38 | #ifdef HAVE_STDDEF_H | ||
39 | # include <stddef.h> | ||
40 | #endif /* HAVE_STDDEF_H */ | ||
41 | #ifdef HAVE_STRING_H | ||
42 | # include <string.h> | ||
43 | #endif /* HAVE_STRING_H */ | ||
44 | #ifdef HAVE_SYS_SYSCTL_H | ||
45 | # include <sys/sysctl.h> | ||
46 | #endif /* HAVE_SYS_SYSCTL_H */ | ||
47 | #ifdef HAVE_FEATURES_H | ||
48 | # include <features.h> | ||
49 | #endif /* HAVE_FEATURES_H */ | ||
50 | #ifdef HAVE_UNISTD_H | ||
51 | # include <unistd.h> | ||
52 | #endif /* HAVE_UNISTD_H */ | ||
53 | #ifdef HAVE_VXCPULIB_H | ||
54 | # include <vxCpuLib.h> | ||
55 | #endif | ||
56 | #ifdef HAVE_WINDOWS_H | ||
57 | # ifndef WIN32_LEAN_AND_MEAN | ||
58 | # define WIN32_LEAN_AND_MEAN 1 | ||
59 | # endif /* ! WIN32_LEAN_AND_MEAN */ | ||
60 | # include <windows.h> | ||
61 | # ifndef ALL_PROCESSOR_GROUPS | ||
62 | # define ALL_PROCESSOR_GROUPS 0xFFFFu | ||
63 | # endif /* ALL_PROCESSOR_GROUPS */ | ||
64 | #elif defined(_WIN32) && ! defined (__CYGWIN__) | ||
65 | # error Windows headers are required for Windows build | ||
66 | #endif /* HAVE_WINDOWS_H */ | ||
67 | #ifdef HAVE_SCHED_H | ||
68 | # include <sched.h> | ||
69 | #endif /* HAVE_SCHED_H */ | ||
70 | #ifdef HAVE_SYS_CPUSET_H | ||
71 | # include <sys/cpuset.h> | ||
72 | #endif /* HAVE_SYS_CPUSET_H */ | ||
73 | |||
74 | #if ! defined(HAS_DECL_CPU_SETSIZE) && ! defined(CPU_SETSIZE) | ||
75 | # define CPU_SETSIZE (1024) | ||
76 | # define CPU_SETSIZE_SAFE (64) | ||
77 | #else /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */ | ||
78 | # define CPU_SETSIZE_SAFE CPU_SETSIZE | ||
79 | #endif /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */ | ||
80 | |||
81 | /* Check and fix possible missing macros */ | ||
82 | #if ! defined(HAS_DECL_CTL_HW) && defined(CTL_HW) | ||
83 | # define HAS_DECL_CTL_HW 1 | ||
84 | #endif /* ! HAS_DECL_CTL_HW && CTL_HW */ | ||
85 | |||
86 | #if ! defined(HAS_DECL_HW_NCPUONLINE) && defined(HW_NCPUONLINE) | ||
87 | # define HAS_DECL_HW_NCPUONLINE 1 | ||
88 | #endif /* ! HAS_DECL_HW_NCPUONLINE && HW_NCPUONLINE */ | ||
89 | |||
90 | #if ! defined(HAS_DECL_HW_AVAILCPU) && defined(HW_AVAILCPU) | ||
91 | # define HAS_DECL_HW_AVAILCPU 1 | ||
92 | #endif /* ! HAS_DECL_HW_AVAILCPU && HW_AVAILCPU */ | ||
93 | |||
94 | #if ! defined(HAS_DECL_HW_NCPU) && defined(HW_NCPU) | ||
95 | # define HAS_DECL_HW_NCPU 1 | ||
96 | #endif /* ! HAS_DECL_HW_NCPU && HW_NCPU */ | ||
97 | |||
98 | #if ! defined(HAS_DECL__SC_NPROCESSORS_ONLN) && defined(_SC_NPROCESSORS_ONLN) | ||
99 | # define HAS_DECL__SC_NPROCESSORS_ONLN 1 | ||
100 | #endif /* ! HAS_DECL__SC_NPROCESSORS_ONLN && _SC_NPROCESSORS_ONLN */ | ||
101 | |||
102 | #if ! defined(HAS_DECL__SC_NPROC_ONLN) && defined(_SC_NPROC_ONLN) | ||
103 | # define HAS_DECL__SC_NPROC_ONLN 1 | ||
104 | #endif /* ! HAS_DECL__SC_NPROC_ONLN && _SC_NPROC_ONLN */ | ||
105 | |||
106 | #if ! defined(HAS_DECL__SC_CRAY_NCPU) && defined(_SC_CRAY_NCPU) | ||
107 | # define HAS_DECL__SC_CRAY_NCPU 1 | ||
108 | #endif /* ! HAS_DECL__SC_CRAY_NCPU && _SC_CRAY_NCPU */ | ||
109 | |||
110 | #if ! defined(HAS_DECL__SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_CONF) | ||
111 | # define HAS_DECL__SC_NPROCESSORS_CONF 1 | ||
112 | #endif /* ! HAVE_DECL__SC_NPROCESSORS_CONF && _SC_NPROCESSORS_CONF */ | ||
113 | |||
114 | /* Forward declarations */ | ||
115 | |||
116 | static int | ||
117 | mhd_tool_get_sys_cpu_count_sysctl_ (void); | ||
118 | |||
119 | /** | ||
120 | * Detect the number of logical CPU cores available for the process by | ||
121 | * sched_getaffinity() (and related) function. | ||
122 | * @return the number of detected logical CPU cores or | ||
123 | * -1 if failed to detect (or this function unavailable). | ||
124 | */ | ||
125 | static int | ||
126 | mhd_tool_get_proc_cpu_count_sched_getaffinity_ (void) | ||
127 | { | ||
128 | int ret = -1; | ||
129 | #if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_GETPID) | ||
130 | /* Glibc style */ | ||
131 | if (0 >= ret) | ||
132 | { | ||
133 | cpu_set_t cur_set; | ||
134 | if (0 == sched_getaffinity (getpid (), sizeof(cur_set), &cur_set)) | ||
135 | { | ||
136 | #ifdef HAVE_CPU_COUNT | ||
137 | ret = CPU_COUNT (&cur_set); | ||
138 | #else /* ! HAVE_CPU_COUNT */ | ||
139 | unsigned int i; | ||
140 | ret = 0; | ||
141 | for (i = 0; i < CPU_SETSIZE_SAFE; ++i) | ||
142 | { | ||
143 | if (CPU_ISSET (i, &cur_set)) | ||
144 | ++ret; | ||
145 | } | ||
146 | if (0 == ret) | ||
147 | ret = -1; | ||
148 | #endif /* ! HAVE_CPU_COUNT */ | ||
149 | } | ||
150 | } | ||
151 | #ifdef HAVE_CPU_COUNT_S | ||
152 | if (0 >= ret) | ||
153 | { | ||
154 | /* Use 256 times larger size than size for default maximum CPU number. | ||
155 | Hopefully it would be enough even for exotic situations. */ | ||
156 | static const unsigned int set_size_cpus = 256 * CPU_SETSIZE; | ||
157 | const size_t set_size_bytes = CPU_ALLOC_SIZE (set_size_cpus); | ||
158 | cpu_set_t *p_set; | ||
159 | |||
160 | p_set = CPU_ALLOC (set_size_cpus); | ||
161 | if (NULL != p_set) | ||
162 | { | ||
163 | if (0 == sched_getaffinity (getpid (), set_size_bytes, p_set)) | ||
164 | { | ||
165 | #ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS | ||
166 | ret = CPU_COUNT_S (set_size_bytes, p_set); | ||
167 | #else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
168 | ret = CPU_COUNT_S (set_size_cpus, p_set); | ||
169 | #endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
170 | } | ||
171 | CPU_FREE (p_set); | ||
172 | } | ||
173 | } | ||
174 | #endif /* HAVE_CPU_COUNT_S */ | ||
175 | #endif /* HAVE_SCHED_GETAFFINITY && HAVE_GETPID */ | ||
176 | if (0 >= ret) | ||
177 | return -1; | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Detect the number of logical CPU cores available for the process by | ||
184 | * cpuset_getaffinity() function. | ||
185 | * @return the number of detected logical CPU cores or | ||
186 | * -1 if failed to detect (or this function unavailable). | ||
187 | */ | ||
188 | static int | ||
189 | mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (void) | ||
190 | { | ||
191 | int ret = -1; | ||
192 | #if defined(HAVE_CPUSET_GETAFFINITY) | ||
193 | /* FreeBSD style */ | ||
194 | if (0 >= ret) | ||
195 | { | ||
196 | cpuset_t cur_mask; | ||
197 | /* The should get "anonymous" mask/set. The anonymous mask is always | ||
198 | a subset of the assigned set (which is a subset of the root set). */ | ||
199 | if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, | ||
200 | sizeof(cur_mask), &cur_mask)) | ||
201 | { | ||
202 | #ifdef HAVE_CPU_COUNT | ||
203 | ret = CPU_COUNT (&cur_mask); | ||
204 | #else /* ! HAVE_CPU_COUNT */ | ||
205 | unsigned int i; | ||
206 | ret = 0; | ||
207 | for (i = 0; i < CPU_SETSIZE_SAFE; ++i) | ||
208 | { | ||
209 | if (CPU_ISSET (i, &cur_mask)) | ||
210 | ++ret; | ||
211 | } | ||
212 | if (0 == ret) | ||
213 | ret = -1; | ||
214 | #endif /* ! HAVE_CPU_COUNT */ | ||
215 | } | ||
216 | } | ||
217 | #ifdef HAVE_CPU_COUNT_S | ||
218 | if (0 >= ret) | ||
219 | { | ||
220 | /* Use 256 times larger size than size for default maximum CPU number. | ||
221 | Hopefully it would be enough even for exotic situations. */ | ||
222 | static const unsigned int mask_size_cpus = 256 * CPU_SETSIZE; | ||
223 | const size_t mask_size_bytes = CPU_ALLOC_SIZE (mask_size_cpus); | ||
224 | cpuset_t *p_mask; | ||
225 | |||
226 | p_mask = CPU_ALLOC (mask_size_cpus); | ||
227 | if (NULL != p_mask) | ||
228 | { | ||
229 | if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, | ||
230 | mask_size_bytes, p_mask)) | ||
231 | { | ||
232 | #ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS | ||
233 | ret = CPU_COUNT_S (mask_size_bytes, p_mask); | ||
234 | #else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
235 | ret = CPU_COUNT_S (mask_size_cpus, p_mask); | ||
236 | #endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
237 | } | ||
238 | CPU_FREE (p_mask); | ||
239 | } | ||
240 | } | ||
241 | #endif /* HAVE_CPU_COUNT_S */ | ||
242 | #endif /* HAVE_CPUSET_GETAFFINITY */ | ||
243 | if (0 >= ret) | ||
244 | return -1; | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Detect the number of logical CPU cores available for the process by | ||
251 | * sched_getaffinity_np() (and related) function. | ||
252 | * @return the number of detected logical CPU cores or | ||
253 | * -1 if failed to detect (or this function unavailable). | ||
254 | */ | ||
255 | static int | ||
256 | mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ (void) | ||
257 | { | ||
258 | int ret = -1; | ||
259 | #if defined(HAVE_SCHED_GETAFFINITY_NP) && defined(HAVE_GETPID) | ||
260 | /* NetBSD style */ | ||
261 | cpuset_t *cpuset_ptr; | ||
262 | cpuset_ptr = cpuset_create (); | ||
263 | if (NULL != cpuset_ptr) | ||
264 | { | ||
265 | if (0 == sched_getaffinity_np (getpid (), cpuset_size (cpuset_ptr), | ||
266 | cpuset_ptr)) | ||
267 | { | ||
268 | cpuid_t cpu_num; | ||
269 | #if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF) | ||
270 | unsigned int max_num = 0; | ||
271 | long sc_value = -1; | ||
272 | sc_value = sysconf (_SC_NPROCESSORS_ONLN); | ||
273 | if (0 < sc_value) | ||
274 | max_num = (unsigned int) sc_value; | ||
275 | if (0 < max_num) | ||
276 | { | ||
277 | ret = 0; | ||
278 | for (cpu_num = 0; cpu_num < max_num; ++cpu_num) | ||
279 | if (0 < cpuset_isset (cpu_num, cpuset_ptr)) | ||
280 | ++ret; | ||
281 | } | ||
282 | else /* Combined with the next 'if' */ | ||
283 | #endif /* HAVE_SYSCONF && HAVE_DECL__SC_NPROCESSORS_CONF */ | ||
284 | if (1) | ||
285 | { | ||
286 | int res; | ||
287 | cpu_num = 0; | ||
288 | ret = 0; | ||
289 | do | ||
290 | { | ||
291 | res = cpuset_isset (cpu_num++, cpuset_ptr); | ||
292 | if (0 < res) | ||
293 | ++ret; | ||
294 | } while (0 <= res); | ||
295 | } | ||
296 | #ifdef __NetBSD__ | ||
297 | if (0 == ret) | ||
298 | { | ||
299 | /* On NetBSD "unset" affinity (exactly zero CPUs) means | ||
300 | "all CPUs are available". */ | ||
301 | ret = mhd_tool_get_sys_cpu_count_sysctl_ (); | ||
302 | } | ||
303 | #endif /* __NetBSD__ */ | ||
304 | } | ||
305 | cpuset_destroy (cpuset_ptr); | ||
306 | } | ||
307 | #endif /* HAVE_SCHED_GETAFFINITY_NP && HAVE_GETPID */ | ||
308 | if (0 >= ret) | ||
309 | return -1; | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | |||
314 | /** | ||
315 | * Detect the number of logical CPU cores available for the process. | ||
316 | * The number of cores available for this process could be different from | ||
317 | * value of cores available on the system. The OS may have limit on number | ||
318 | * assigned/allowed cores for single process and process may have limited | ||
319 | * CPU affinity. | ||
320 | * @return the number of logical CPU cores available for the process or | ||
321 | * -1 if failed to detect | ||
322 | */ | ||
323 | int | ||
324 | mhd_tool_get_proc_cpu_count (void) | ||
325 | { | ||
326 | int res; | ||
327 | |||
328 | #if defined(__linux__) || defined(__GLIBC__) | ||
329 | /* On Linux kernel try first 'sched_getaffinity()' as it should be | ||
330 | the native API. | ||
331 | Also try it first on other kernels if Glibc is used. */ | ||
332 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ (); | ||
333 | if (0 < res) | ||
334 | return res; | ||
335 | |||
336 | res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (); | ||
337 | if (0 < res) | ||
338 | return res; | ||
339 | #else /* ! __linux__ && ! __GLIBC__ */ | ||
340 | /* On non-Linux kernels 'cpuset_getaffinity()' could be the native API, | ||
341 | while 'sched_getaffinity()' could be implemented in compatibility layer. */ | ||
342 | res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (); | ||
343 | if (0 < res) | ||
344 | return res; | ||
345 | |||
346 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ (); | ||
347 | if (0 < res) | ||
348 | return res; | ||
349 | #endif /* ! __linux__ && ! __GLIBC__ */ | ||
350 | |||
351 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ (); | ||
352 | if (0 < res) | ||
353 | return res; | ||
354 | |||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Detect the number of processors by special API functions | ||
361 | * @return number of processors as returned by special API functions or | ||
362 | * -1 in case of error or special API functions unavailable | ||
363 | */ | ||
364 | static int | ||
365 | mhd_tool_get_sys_cpu_count_special_api_ (void) | ||
366 | { | ||
367 | int ret = -1; | ||
368 | #ifdef HAVE_PSTAT_GETDYNAMIC | ||
369 | if (0 >= ret) | ||
370 | { | ||
371 | /* HP-UX things */ | ||
372 | struct pst_dynamic psd_data; | ||
373 | memset ((void *) &psd_data, 0, sizeof(psd_data)); | ||
374 | if (1 == pstat_getdynamic (&psd_data, sizeof(psd_data), (size_t) 1, 0)) | ||
375 | { | ||
376 | if (0 < psd_data.psd_proc_cnt) | ||
377 | ret = (int) psd_data.psd_proc_cnt; | ||
378 | } | ||
379 | } | ||
380 | #endif /* HAVE_PSTAT_GETDYNAMIC */ | ||
381 | #ifdef HAVE_VXCPUENABLEDGET | ||
382 | if (0 >= ret) | ||
383 | { | ||
384 | /* VxWorks */ | ||
385 | cpuset_t enb_set; | ||
386 | enb_set = vxCpuEnabledGet (); | ||
387 | /* Count set bits */ | ||
388 | for (ret = 0; 0 != enb_set; enb_set &= enb_set - 1) | ||
389 | ++ret; | ||
390 | } | ||
391 | #endif /* HAVE_VXCPUENABLEDGET */ | ||
392 | #if defined(_WIN32) && ! defined (__CYGWIN__) | ||
393 | if (0 >= ret) | ||
394 | { | ||
395 | /* Native W32 */ | ||
396 | HMODULE k32hndl; | ||
397 | k32hndl = GetModuleHandleA ("kernel32.dll"); | ||
398 | if (NULL != k32hndl) | ||
399 | { | ||
400 | typedef DWORD (WINAPI *GAPC_PTR)(WORD GroupNumber); | ||
401 | GAPC_PTR ptrGetActiveProcessorCount; | ||
402 | /* Available on W7 or later */ | ||
403 | ptrGetActiveProcessorCount = | ||
404 | (GAPC_PTR) (void *) GetProcAddress (k32hndl, "GetActiveProcessorCount"); | ||
405 | if (NULL != ptrGetActiveProcessorCount) | ||
406 | { | ||
407 | DWORD res; | ||
408 | res = ptrGetActiveProcessorCount (ALL_PROCESSOR_GROUPS); | ||
409 | ret = (int) res; | ||
410 | if (res != (DWORD) ret) | ||
411 | ret = -1; /* Overflow */ | ||
412 | } | ||
413 | } | ||
414 | if ((0 >= ret) && (NULL != k32hndl)) | ||
415 | { | ||
416 | typedef void (WINAPI *GNSI_PTR)(SYSTEM_INFO *pSysInfo); | ||
417 | GNSI_PTR ptrGetNativeSystemInfo; | ||
418 | /* May give incorrect (low) result on versions from W7 to W11 | ||
419 | when more then 64 CPUs are available */ | ||
420 | ptrGetNativeSystemInfo = | ||
421 | (GNSI_PTR) (void *) GetProcAddress (k32hndl, "GetNativeSystemInfo"); | ||
422 | if (NULL != ptrGetNativeSystemInfo) | ||
423 | { | ||
424 | SYSTEM_INFO sysInfo; | ||
425 | |||
426 | memset ((void *) &sysInfo, 0, sizeof(sysInfo)); | ||
427 | ptrGetNativeSystemInfo (&sysInfo); | ||
428 | ret = (int) sysInfo.dwNumberOfProcessors; | ||
429 | if (sysInfo.dwNumberOfProcessors != (DWORD) ret) | ||
430 | ret = -1; /* Overflow */ | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | if (0 >= ret) | ||
435 | { | ||
436 | /* May give incorrect (low) result on versions from W7 to W11 | ||
437 | when more then 64 CPUs are available */ | ||
438 | SYSTEM_INFO sysInfo; | ||
439 | memset ((void *) &sysInfo, 0, sizeof(sysInfo)); | ||
440 | GetSystemInfo (&sysInfo); | ||
441 | ret = (int) sysInfo.dwNumberOfProcessors; | ||
442 | if (sysInfo.dwNumberOfProcessors != (DWORD) ret) | ||
443 | ret = -1; /* Overflow */ | ||
444 | } | ||
445 | #endif /* _WIN32 && ! __CYGWIN__ */ | ||
446 | if (0 >= ret) | ||
447 | return -1; | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | |||
452 | /** | ||
453 | * Detect the number of processors by sysctl*() functions | ||
454 | * @return number of processors as returned by 'sysctl*' functions or | ||
455 | * -1 in case of error or the number cannot be detected | ||
456 | * by these functions | ||
457 | */ | ||
458 | static int | ||
459 | mhd_tool_get_sys_cpu_count_sysctl_ (void) | ||
460 | { | ||
461 | int ret = -1; | ||
462 | /* Do not use sysctl() function on GNU/Linux even if | ||
463 | sysctl() is available */ | ||
464 | #ifndef __linux__ | ||
465 | #ifdef HAVE_SYSCTLBYNAME | ||
466 | if (0 >= ret) | ||
467 | { | ||
468 | size_t value_size = sizeof(ret); | ||
469 | /* Darwin: The number of available logical CPUs */ | ||
470 | if ((0 != sysctlbyname ("hw.logicalcpu", &ret, &value_size, | ||
471 | NULL, 0)) | ||
472 | || (sizeof(ret) != value_size)) | ||
473 | ret = -1; | ||
474 | } | ||
475 | if (0 >= ret) | ||
476 | { | ||
477 | size_t value_size = sizeof(ret); | ||
478 | /* FreeBSD: The number of online CPUs */ | ||
479 | if ((0 != sysctlbyname ("kern.smp.cpus", &ret, &value_size, | ||
480 | NULL, 0)) | ||
481 | || (sizeof(ret) != value_size)) | ||
482 | ret = -1; | ||
483 | } | ||
484 | if (0 >= ret) | ||
485 | { | ||
486 | size_t value_size = sizeof(ret); | ||
487 | /* Darwin: The current number of CPUs available to run threads */ | ||
488 | if ((0 != sysctlbyname ("hw.activecpu", &ret, &value_size, | ||
489 | NULL, 0)) | ||
490 | || (sizeof(ret) != value_size)) | ||
491 | ret = -1; | ||
492 | } | ||
493 | if (0 >= ret) | ||
494 | { | ||
495 | size_t value_size = sizeof(ret); | ||
496 | /* OpenBSD, NetBSD: The number of online CPUs */ | ||
497 | if ((0 != sysctlbyname ("hw.ncpuonline", &ret, &value_size, | ||
498 | NULL, 0)) | ||
499 | || (sizeof(ret) != value_size)) | ||
500 | ret = -1; | ||
501 | } | ||
502 | if (0 >= ret) | ||
503 | { | ||
504 | size_t value_size = sizeof(ret); | ||
505 | /* Darwin: The old/alternative name for "hw.activecpu" */ | ||
506 | if ((0 != sysctlbyname ("hw.availcpu", &ret, &value_size, | ||
507 | NULL, 0)) | ||
508 | || (sizeof(ret) != value_size)) | ||
509 | ret = -1; | ||
510 | } | ||
511 | #endif /* HAVE_SYSCTLBYNAME */ | ||
512 | #if defined(HAVE_SYSCTL) && \ | ||
513 | defined(HAS_DECL_CTL_HW) && \ | ||
514 | defined(HAS_DECL_HW_NCPUONLINE) | ||
515 | if (0 >= ret) | ||
516 | { | ||
517 | /* OpenBSD, NetBSD: The number of online CPUs */ | ||
518 | int mib[2] = { CTL_HW, HW_NCPUONLINE }; | ||
519 | size_t value_size = sizeof(ret); | ||
520 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
521 | || (sizeof(ret) != value_size)) | ||
522 | ret = -1; | ||
523 | } | ||
524 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPUONLINE */ | ||
525 | #if defined(HAVE_SYSCTL) && \ | ||
526 | defined(HAS_DECL_CTL_HW) && \ | ||
527 | defined(HAS_DECL_HW_AVAILCPU) | ||
528 | if (0 >= ret) | ||
529 | { | ||
530 | /* Darwin: The MIB name for "hw.activecpu" */ | ||
531 | int mib[2] = { CTL_HW, HW_AVAILCPU }; | ||
532 | size_t value_size = sizeof(ret); | ||
533 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
534 | || (sizeof(ret) != value_size)) | ||
535 | ret = -1; | ||
536 | } | ||
537 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_AVAILCPU */ | ||
538 | #ifdef HAVE_SYSCTLBYNAME | ||
539 | if (0 >= ret) | ||
540 | { | ||
541 | size_t value_size = sizeof(ret); | ||
542 | /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */ | ||
543 | if ((0 != sysctlbyname ("hw.ncpu", &ret, &value_size, | ||
544 | NULL, 0)) | ||
545 | || (sizeof(ret) != value_size)) | ||
546 | ret = -1; | ||
547 | } | ||
548 | #endif /* HAVE_SYSCTLBYNAME */ | ||
549 | #if defined(HAVE_SYSCTL) && \ | ||
550 | defined(HAS_DECL_CTL_HW) && \ | ||
551 | defined(HAS_DECL_HW_NCPU) | ||
552 | if (0 >= ret) | ||
553 | { | ||
554 | /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */ | ||
555 | int mib[2] = { CTL_HW, HW_NCPU }; | ||
556 | size_t value_size = sizeof(ret); | ||
557 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
558 | || (sizeof(ret) != value_size)) | ||
559 | ret = -1; | ||
560 | } | ||
561 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPU */ | ||
562 | #endif /* ! __linux__ */ | ||
563 | if (0 >= ret) | ||
564 | return -1; | ||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | |||
569 | /** | ||
570 | * Detect the number of processors by sysconf() function | ||
571 | * @return number of processors as returned by 'sysconf' function or | ||
572 | * -1 in case of error or 'sysconf' unavailable | ||
573 | */ | ||
574 | static int | ||
575 | mhd_tool_get_sys_cpu_count_sysconf_ (void) | ||
576 | { | ||
577 | int ret = -1; | ||
578 | #if defined(HAVE_SYSCONF) && \ | ||
579 | (defined(HAS_DECL__SC_NPROCESSORS_ONLN) || \ | ||
580 | defined(HAS_DECL__SC_NPROC_ONLN) || \ | ||
581 | defined(HAS_DECL__SC_CRAY_NCPU)) | ||
582 | long value = -1; | ||
583 | #ifdef HAS_DECL__SC_NPROCESSORS_ONLN | ||
584 | if (0 >= value) | ||
585 | value = sysconf (_SC_NPROCESSORS_ONLN); | ||
586 | #endif /* HAS_DECL__SC_NPROCESSORS_ONLN */ | ||
587 | #ifdef HAS_DECL__SC_NPROC_ONLN | ||
588 | if (0 >= value) | ||
589 | value = sysconf (_SC_NPROC_ONLN); | ||
590 | #endif /* HAS_DECL__SC_NPROC_ONLN */ | ||
591 | #ifdef HAS_DECL__SC_CRAY_NCPU | ||
592 | if (0 >= value) | ||
593 | value = sysconf (_SC_CRAY_NCPU); | ||
594 | #endif /* HAS_DECL__SC_CRAY_NCPU */ | ||
595 | if (0 >= value) | ||
596 | return -1; | ||
597 | ret = (int) value; | ||
598 | if ((long) ret != value) | ||
599 | return -1; /* Overflow */ | ||
600 | #endif /* HAVE_SYSCONF && | ||
601 | (HAS_DECL__SC_NPROCESSORS_ONLN || HAS_DECL__SC_NPROC_ONLN || | ||
602 | HAS_DECL__SC_CRAY_NCPU) */ | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | |||
607 | /** | ||
608 | * Try to detect the number of logical CPU cores available for the system. | ||
609 | * The number of available logical CPU cores could be changed any time due to | ||
610 | * CPU hotplug. | ||
611 | * @return the number of logical CPU cores available, | ||
612 | * -1 if failed to detect. | ||
613 | */ | ||
614 | int | ||
615 | mhd_tool_get_system_cpu_count (void) | ||
616 | { | ||
617 | int res; | ||
618 | |||
619 | /* Try specialised APIs first */ | ||
620 | res = mhd_tool_get_sys_cpu_count_special_api_ (); | ||
621 | if (0 < res) | ||
622 | return res; | ||
623 | |||
624 | /* Try sysctl*(). This is typically a direct interface to | ||
625 | kernel values. */ | ||
626 | res = mhd_tool_get_sys_cpu_count_sysctl_ (); | ||
627 | if (0 < res) | ||
628 | return res; | ||
629 | |||
630 | /* Try sysconf() as the last resort as this is a generic interface | ||
631 | which can be implemented by parsing system files. */ | ||
632 | res = mhd_tool_get_sys_cpu_count_sysconf_ (); | ||
633 | #if ! defined(__linux__) && ! defined(__GLIBC__) | ||
634 | if (0 < res) | ||
635 | return res; | ||
636 | #else /* __linux__ || __GLIBC__ */ | ||
637 | if (2 < res) | ||
638 | return res; | ||
639 | if (0 < res) | ||
640 | { | ||
641 | /* '1' or '2' could a be fallback number. | ||
642 | * See get_nprocs_fallback() in glibc | ||
643 | sysdeps/unix/sysv/linux/getsysstats.c */ | ||
644 | |||
645 | int proc_cpu_count; | ||
646 | |||
647 | proc_cpu_count = mhd_tool_get_proc_cpu_count (); | ||
648 | if ((0 < proc_cpu_count) && (proc_cpu_count <= res)) | ||
649 | { | ||
650 | /* The detected number of CPUs available for the process | ||
651 | is 1 or 2 and fits detected number of system CPUS. | ||
652 | Assume detected number is correct. */ | ||
653 | return res; | ||
654 | } | ||
655 | } | ||
656 | #endif /* __linux__ || __GLIBC__ */ | ||
657 | return -1; /* Cannot detect */ | ||
658 | } | ||