aboutsummaryrefslogtreecommitdiff
path: root/src/tools/mhd_tool_get_cpu_count.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/mhd_tool_get_cpu_count.c')
-rw-r--r--src/tools/mhd_tool_get_cpu_count.c658
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
116static int
117mhd_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 */
125static int
126mhd_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 */
188static int
189mhd_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 */
255static int
256mhd_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 */
323int
324mhd_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 */
364static int
365mhd_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 */
458static int
459mhd_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 */
574static int
575mhd_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 */
614int
615mhd_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}