GNU libmicrohttpd 1.0.2
Loading...
Searching...
No Matches
mhd_tool_get_cpu_count.c
Go to the documentation of this file.
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
26
27#include "mhd_options.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#ifdef HAVE_STDBOOL_H
74# include <stdbool.h>
75#endif /* HAVE_STDBOOL_H */
76
77#if ! defined(HAS_DECL_CPU_SETSIZE) && ! defined(CPU_SETSIZE)
78# define CPU_SETSIZE (1024)
79# define CPU_SETSIZE_SAFE (64)
80#else /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */
81# define CPU_SETSIZE_SAFE CPU_SETSIZE
82#endif /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */
83
84/* Check and fix possible missing macros */
85#if ! defined(HAS_DECL_CTL_HW) && defined(CTL_HW)
86# define HAS_DECL_CTL_HW 1
87#endif /* ! HAS_DECL_CTL_HW && CTL_HW */
88
89#if ! defined(HAS_DECL_HW_NCPUONLINE) && defined(HW_NCPUONLINE)
90# define HAS_DECL_HW_NCPUONLINE 1
91#endif /* ! HAS_DECL_HW_NCPUONLINE && HW_NCPUONLINE */
92
93#if ! defined(HAS_DECL_HW_AVAILCPU) && defined(HW_AVAILCPU)
94# define HAS_DECL_HW_AVAILCPU 1
95#endif /* ! HAS_DECL_HW_AVAILCPU && HW_AVAILCPU */
96
97#if ! defined(HAS_DECL_HW_NCPU) && defined(HW_NCPU)
98# define HAS_DECL_HW_NCPU 1
99#endif /* ! HAS_DECL_HW_NCPU && HW_NCPU */
100
101#if ! defined(HAS_DECL__SC_NPROCESSORS_ONLN) && defined(_SC_NPROCESSORS_ONLN)
102# define HAS_DECL__SC_NPROCESSORS_ONLN 1
103#endif /* ! HAS_DECL__SC_NPROCESSORS_ONLN && _SC_NPROCESSORS_ONLN */
104
105#if ! defined(HAS_DECL__SC_NPROC_ONLN) && defined(_SC_NPROC_ONLN)
106# define HAS_DECL__SC_NPROC_ONLN 1
107#endif /* ! HAS_DECL__SC_NPROC_ONLN && _SC_NPROC_ONLN */
108
109#if ! defined(HAS_DECL__SC_CRAY_NCPU) && defined(_SC_CRAY_NCPU)
110# define HAS_DECL__SC_CRAY_NCPU 1
111#endif /* ! HAS_DECL__SC_CRAY_NCPU && _SC_CRAY_NCPU */
112
113#if ! defined(HAS_DECL__SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_CONF)
114# define HAS_DECL__SC_NPROCESSORS_CONF 1
115#endif /* ! HAVE_DECL__SC_NPROCESSORS_CONF && _SC_NPROCESSORS_CONF */
116
117/* Forward declarations */
118
119static int
121
128static int
130{
131 int ret = -1;
132#if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_GETPID)
133 /* Glibc style */
134 if (0 >= ret)
135 {
136 cpu_set_t cur_set;
137 if (0 == sched_getaffinity (getpid (), sizeof (cur_set), &cur_set))
138 {
139#ifdef HAVE_CPU_COUNT
140 ret = CPU_COUNT (&cur_set);
141#else /* ! HAVE_CPU_COUNT */
142 unsigned int i;
143 ret = 0;
144 for (i = 0; i < CPU_SETSIZE_SAFE; ++i)
145 {
146 if (CPU_ISSET (i, &cur_set))
147 ++ret;
148 }
149 if (0 == ret)
150 ret = -1;
151#endif /* ! HAVE_CPU_COUNT */
152 }
153 }
154#ifdef HAVE_CPU_COUNT_S
155 if (0 >= ret)
156 {
157 /* Use 256 times larger size than size for default maximum CPU number.
158 Hopefully it would be enough even for exotic situations. */
159 static const unsigned int set_size_cpus = 256 * CPU_SETSIZE;
160 const size_t set_size_bytes = CPU_ALLOC_SIZE (set_size_cpus);
161 cpu_set_t *p_set;
162
163 p_set = CPU_ALLOC (set_size_cpus);
164 if (NULL != p_set)
165 {
166 if (0 == sched_getaffinity (getpid (), set_size_bytes, p_set))
167 {
168#ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS
169 ret = CPU_COUNT_S (set_size_bytes, p_set);
170#else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
171 ret = CPU_COUNT_S (set_size_cpus, p_set);
172#endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
173 }
174 CPU_FREE (p_set);
175 }
176 }
177#endif /* HAVE_CPU_COUNT_S */
178#endif /* HAVE_SCHED_GETAFFINITY && HAVE_GETPID */
179 if (0 >= ret)
180 return -1;
181 return ret;
182}
183
184
191static int
193{
194 int ret = -1;
195#if defined(HAVE_CPUSET_GETAFFINITY)
196 /* FreeBSD style */
197 if (0 >= ret)
198 {
199 cpuset_t cur_mask;
200 /* The should get "anonymous" mask/set. The anonymous mask is always
201 a subset of the assigned set (which is a subset of the root set). */
202 if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1,
203 sizeof (cur_mask), &cur_mask))
204 {
205#ifdef HAVE_CPU_COUNT
206 ret = CPU_COUNT (&cur_mask);
207#else /* ! HAVE_CPU_COUNT */
208 unsigned int i;
209 ret = 0;
210 for (i = 0; i < CPU_SETSIZE_SAFE; ++i)
211 {
212 if (CPU_ISSET (i, &cur_mask))
213 ++ret;
214 }
215 if (0 == ret)
216 ret = -1;
217#endif /* ! HAVE_CPU_COUNT */
218 }
219 }
220#ifdef HAVE_CPU_COUNT_S
221 if (0 >= ret)
222 {
223 /* Use 256 times larger size than size for default maximum CPU number.
224 Hopefully it would be enough even for exotic situations. */
225 static const unsigned int mask_size_cpus = 256 * CPU_SETSIZE;
226 const size_t mask_size_bytes = CPU_ALLOC_SIZE (mask_size_cpus);
227 cpuset_t *p_mask;
228
229 p_mask = CPU_ALLOC (mask_size_cpus);
230 if (NULL != p_mask)
231 {
232 if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1,
233 mask_size_bytes, p_mask))
234 {
235#ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS
236 ret = CPU_COUNT_S (mask_size_bytes, p_mask);
237#else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
238 ret = CPU_COUNT_S (mask_size_cpus, p_mask);
239#endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
240 }
241 CPU_FREE (p_mask);
242 }
243 }
244#endif /* HAVE_CPU_COUNT_S */
245#endif /* HAVE_CPUSET_GETAFFINITY */
246 if (0 >= ret)
247 return -1;
248 return ret;
249}
250
251
258static int
260{
261 int ret = -1;
262#if defined(HAVE_SCHED_GETAFFINITY_NP) && defined(HAVE_GETPID)
263 /* NetBSD style */
264 cpuset_t *cpuset_ptr;
265 cpuset_ptr = cpuset_create ();
266 if (NULL != cpuset_ptr)
267 {
268 if (0 == sched_getaffinity_np (getpid (), cpuset_size (cpuset_ptr),
269 cpuset_ptr))
270 {
271 cpuid_t cpu_num;
272#if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF)
273 unsigned int max_num = 0;
274 long sc_value;
275 sc_value = sysconf (_SC_NPROCESSORS_ONLN);
276 if (0 < sc_value)
277 max_num = (unsigned int) sc_value;
278 if (0 < max_num)
279 {
280 ret = 0;
281 for (cpu_num = 0; cpu_num < max_num; ++cpu_num)
282 if (0 < cpuset_isset (cpu_num, cpuset_ptr))
283 ++ret;
284 }
285 else /* Combined with the next 'if' */
286#endif /* HAVE_SYSCONF && HAVE_DECL__SC_NPROCESSORS_CONF */
287 if (1)
288 {
289 int res;
290 cpu_num = 0;
291 ret = 0;
292 do
293 {
294 res = cpuset_isset (cpu_num++, cpuset_ptr);
295 if (0 < res)
296 ++ret;
297 } while (0 <= res);
298 }
299#ifdef __NetBSD__
300 if (0 == ret)
301 {
302 /* On NetBSD "unset" affinity (exactly zero CPUs) means
303 "all CPUs are available". */
305 }
306#endif /* __NetBSD__ */
307 }
308 cpuset_destroy (cpuset_ptr);
309 }
310#endif /* HAVE_SCHED_GETAFFINITY_NP && HAVE_GETPID */
311 if (0 >= ret)
312 return -1;
313 return ret;
314}
315
316
323static int
325{
326 int ret = -1;
327#if defined(_WIN32) && ! defined(__CYGWIN__)
328 /* W32 Native */
333#define MHDT_MAX_GROUP_COUNT 128
337 int count_by_proc_aff_mask;
338 count_by_proc_aff_mask = -1;
339 if (1)
340 {
341 DWORD_PTR proc_aff;
342 DWORD_PTR sys_aff;
343
344 if (GetProcessAffinityMask (GetCurrentProcess (), &proc_aff, &sys_aff))
345 {
346 /* Count all set bits */
347 for (count_by_proc_aff_mask = 0; 0 != proc_aff; proc_aff &= proc_aff - 1)
348 ++count_by_proc_aff_mask;
349 }
350 }
351 if (0 < count_by_proc_aff_mask)
352 {
353 HMODULE k32hndl;
354 k32hndl = LoadLibraryA ("kernel32.dll");
355 if (NULL != k32hndl)
356 {
357 typedef BOOL (WINAPI *GPGA_PTR)(HANDLE hProcess,
358 PUSHORT GroupCount,
359 PUSHORT GroupArray);
360 GPGA_PTR ptrGetProcessGroupAffinity;
361 ptrGetProcessGroupAffinity =
362 (GPGA_PTR) (void *) GetProcAddress (k32hndl,
363 "GetProcessGroupAffinity");
364 if (NULL == ptrGetProcessGroupAffinity)
365 {
366 /* Windows version before Win7 */
367 /* No processor groups supported, the process affinity mask gives full picture */
368 ret = count_by_proc_aff_mask;
369 }
370 else
371 {
372 /* Windows version Win7 or later */
373 /* Processor groups are supported */
374 USHORT arr_elements = MHDT_MAX_GROUP_COUNT;
375 USHORT groups_arr[MHDT_MAX_GROUP_COUNT]; /* Hopefully should be enough */
376 /* Improvement: Implement dynamic allocation when it would be reasonable */
380 bool single_cpu_group_assigned;
381 struct mhdt_GR_AFFINITY
382 {
383 KAFFINITY Mask;
384 WORD Group;
385 WORD Reserved[3];
386 };
387 typedef BOOL (WINAPI *GPDCSM_PTR)(HANDLE Process,
388 struct mhdt_GR_AFFINITY *CpuSetMasks,
389 USHORT CpuSetMaskCount,
390 USHORT *RequiredMaskCount);
391 GPDCSM_PTR ptrGetProcessDefaultCpuSetMasks;
392 bool win_fe_or_later;
393 bool cpu_set_mask_assigned;
394
395 single_cpu_group_assigned = false;
396 if (ptrGetProcessGroupAffinity (GetCurrentProcess (), &arr_elements,
397 groups_arr))
398 {
399 if (1 == arr_elements)
400 {
401 /* Exactly one processor group assigned to the process */
402 single_cpu_group_assigned = true;
403#if 0 /* Disabled code */
404 /* The value returned by GetThreadGroupAffinity() is not relevant as
405 for the new threads the process affinity mask is used. */
406 ULONG_PTR proc_aff2;
407 typedef BOOL (WINAPI *GTGA_PTR)(HANDLE hThread,
408 struct mhdt_GR_AFFINITY *
409 GroupAffinity);
410 GTGA_PTR ptrGetThreadGroupAffinity;
411 ptrGetThreadGroupAffinity =
412 (GTGA_PTR) (void *) GetProcAddress (k32hndl,
413 "GetThreadGroupAffinity");
414 if (NULL != ptrGetThreadGroupAffinity)
415 {
416 struct mhdt_GR_AFFINITY thr_gr_aff;
417 if (ptrGetThreadGroupAffinity (GetCurrentThread (), &thr_gr_aff))
418 proc_aff2 = (ULONG_PTR) thr_gr_aff.Mask;
419 }
420#endif /* Disabled code */
421 }
422 }
423 ptrGetProcessDefaultCpuSetMasks =
424 (GPDCSM_PTR) (void *) GetProcAddress (k32hndl,
425 "GetProcessDefaultCpuSetMasks");
426 if (NULL != ptrGetProcessDefaultCpuSetMasks)
427 {
428 /* This is Iron Release / Codename Fe
429 (also know as Windows 11 and Windows Server 2022)
430 or later version */
431 struct mhdt_GR_AFFINITY gr_affs[MHDT_MAX_GROUP_COUNT]; /* Hopefully should be enough */
432 /* Improvement: Implement dynamic allocation when it would be reasonable */
433 USHORT num_elm;
434
435 win_fe_or_later = true;
436
437 if (ptrGetProcessDefaultCpuSetMasks (GetCurrentProcess (), gr_affs,
438 sizeof (gr_affs)
439 / sizeof (gr_affs[0]), &num_elm))
440 {
441 if (0 == num_elm)
442 {
443 /* No group mask set */
444 cpu_set_mask_assigned = false;
445 }
446 else
447 cpu_set_mask_assigned = true;
448 }
449 else
450 cpu_set_mask_assigned = true; /* Assume the worst case */
451 }
452 else
453 {
454 win_fe_or_later = false;
455 cpu_set_mask_assigned = false;
456 }
457 if (! win_fe_or_later)
458 {
459 /* The OS is not capable of distributing threads across different
460 processor groups. Results reported by GetProcessAffinityMask()
461 are relevant for the main processor group for the process. */
462 ret = count_by_proc_aff_mask;
463 }
464 else
465 {
466 /* The of is capable of automatic threads distribution across
467 processor groups. */
468 if (cpu_set_mask_assigned)
469 {
470 /* Assigned Default CpuSet Masks combines with "classic"
471 affinity in the not fully clear way. The combination
472 is not documented and this functionality could be changed
473 any moment. */
474 ret = -1;
475 }
476 else
477 {
478 if (! single_cpu_group_assigned)
479 {
480 /* This is a multi processor group process on Win11 (or later).
481 Each processor group may have different affinity and
482 the OS has not API to get it.
483 For example, affinity to the main processor group could be
484 assigned by SetProcessAffinityMask() function, which converts
485 the process to the single-processor-group type, but if
486 SetThreadGroupAffinity() is called later and bind the thread
487 to another processor group, the process becomes multi-processor-
488 group again, however the initial affinity mask is still used
489 for the initial (main) processor group. There is no API to read
490 it.
491 It is also possible that processor groups have different number
492 of processors. */
493 ret = -1;
494 }
495 else
496 {
497 /* Single-processor-group process on Win11 (or later) without
498 assigned Default CpuSet Masks. */
499 ret = count_by_proc_aff_mask;
500 }
501 }
502 }
503 }
504 FreeLibrary (k32hndl);
505 }
506 }
507#endif /* _WIN32 && ! __CYGWIN__ */
508 if (0 >= ret)
509 return -1;
510 return ret;
511}
512
513
523int
525{
526 int res;
527
528#if defined(__linux__) || defined(__GLIBC__)
529 /* On Linux kernel try first 'sched_getaffinity()' as it should be
530 the native API.
531 Also try it first on other kernels if Glibc is used. */
533 if (0 < res)
534 return res;
535
537 if (0 < res)
538 return res;
539#else /* ! __linux__ && ! __GLIBC__ */
540 /* On non-Linux kernels 'cpuset_getaffinity()' could be the native API,
541 while 'sched_getaffinity()' could be implemented in compatibility layer. */
543 if (0 < res)
544 return res;
545
547 if (0 < res)
548 return res;
549#endif /* ! __linux__ && ! __GLIBC__ */
550
552 if (0 < res)
553 return res;
554
556 if (0 < res)
557 return res;
558
559 return -1;
560}
561
562
568static int
570{
571 int ret = -1;
572#ifdef HAVE_PSTAT_GETDYNAMIC
573 if (0 >= ret)
574 {
575 /* HP-UX things */
576 struct pst_dynamic psd_data;
577 memset ((void *) &psd_data, 0, sizeof (psd_data));
578 if (1 == pstat_getdynamic (&psd_data, sizeof (psd_data), (size_t) 1, 0))
579 {
580 if (0 < psd_data.psd_proc_cnt)
581 ret = (int) psd_data.psd_proc_cnt;
582 }
583 }
584#endif /* HAVE_PSTAT_GETDYNAMIC */
585#ifdef HAVE_VXCPUENABLEDGET
586 if (0 >= ret)
587 {
588 /* VxWorks */
589 cpuset_t enb_set;
590 enb_set = vxCpuEnabledGet ();
591 /* Count set bits */
592 for (ret = 0; 0 != enb_set; enb_set &= enb_set - 1)
593 ++ret;
594 }
595#endif /* HAVE_VXCPUENABLEDGET */
596#if defined(_WIN32) && ! defined (__CYGWIN__)
597 if (0 >= ret)
598 {
599 /* Native W32 */
600 HMODULE k32hndl;
601 k32hndl = LoadLibraryA ("kernel32.dll");
602 if (NULL != k32hndl)
603 {
604 typedef DWORD (WINAPI *GAPC_PTR)(WORD GroupNumber);
605 GAPC_PTR ptrGetActiveProcessorCount;
606 /* Available on W7 or later */
607 ptrGetActiveProcessorCount =
608 (GAPC_PTR) (void *) GetProcAddress (k32hndl, "GetActiveProcessorCount");
609 if (NULL != ptrGetActiveProcessorCount)
610 {
611 DWORD res;
612 res = ptrGetActiveProcessorCount (ALL_PROCESSOR_GROUPS);
613 ret = (int) res;
614 if (res != (DWORD) ret)
615 ret = -1; /* Overflow */
616 }
617 }
618 if ((0 >= ret) && (NULL != k32hndl))
619 {
620 typedef void (WINAPI *GNSI_PTR)(SYSTEM_INFO *pSysInfo);
621 GNSI_PTR ptrGetNativeSystemInfo;
622 /* May give incorrect (low) result on versions from W7 to W11
623 when more then 64 CPUs are available */
624 ptrGetNativeSystemInfo =
625 (GNSI_PTR) (void *) GetProcAddress (k32hndl, "GetNativeSystemInfo");
626 if (NULL != ptrGetNativeSystemInfo)
627 {
628 SYSTEM_INFO sysInfo;
629
630 memset ((void *) &sysInfo, 0, sizeof (sysInfo));
631 ptrGetNativeSystemInfo (&sysInfo);
632 ret = (int) sysInfo.dwNumberOfProcessors;
633 if (sysInfo.dwNumberOfProcessors != (DWORD) ret)
634 ret = -1; /* Overflow */
635 }
636 }
637 if (NULL != k32hndl)
638 FreeLibrary (k32hndl);
639 }
640 if (0 >= ret)
641 {
642 /* May give incorrect (low) result on versions from W7 to W11
643 when more then 64 CPUs are available */
644 SYSTEM_INFO sysInfo;
645 memset ((void *) &sysInfo, 0, sizeof (sysInfo));
646 GetSystemInfo (&sysInfo);
647 ret = (int) sysInfo.dwNumberOfProcessors;
648 if (sysInfo.dwNumberOfProcessors != (DWORD) ret)
649 ret = -1; /* Overflow */
650 }
651#endif /* _WIN32 && ! __CYGWIN__ */
652 if (0 >= ret)
653 return -1;
654 return ret;
655}
656
657
667static int
669{
670 int ret = -1;
671 /* Do not use sysctl() function on GNU/Linux even if
672 sysctl() is available */
673#ifndef __linux__
674#ifdef HAVE_SYSCTLBYNAME
675 if (0 >= ret)
676 {
677 size_t value_size = sizeof (ret);
678 /* Darwin: The number of available logical CPUs */
679 if ((0 != sysctlbyname ("hw.logicalcpu", &ret, &value_size,
680 NULL, 0))
681 || (sizeof (ret) != value_size))
682 ret = -1;
683 }
684 if (0 >= ret)
685 {
686 size_t value_size = sizeof (ret);
687 /* FreeBSD: The number of online CPUs */
688 if ((0 != sysctlbyname ("kern.smp.cpus", &ret, &value_size,
689 NULL, 0))
690 || (sizeof (ret) != value_size))
691 ret = -1;
692 }
693 if (0 >= ret)
694 {
695 size_t value_size = sizeof (ret);
696 /* Darwin: The current number of CPUs available to run threads */
697 if ((0 != sysctlbyname ("hw.activecpu", &ret, &value_size,
698 NULL, 0))
699 || (sizeof (ret) != value_size))
700 ret = -1;
701 }
702 if (0 >= ret)
703 {
704 size_t value_size = sizeof (ret);
705 /* OpenBSD, NetBSD: The number of online CPUs */
706 if ((0 != sysctlbyname ("hw.ncpuonline", &ret, &value_size,
707 NULL, 0))
708 || (sizeof (ret) != value_size))
709 ret = -1;
710 }
711 if (0 >= ret)
712 {
713 size_t value_size = sizeof (ret);
714 /* Darwin: The old/alternative name for "hw.activecpu" */
715 if ((0 != sysctlbyname ("hw.availcpu", &ret, &value_size,
716 NULL, 0))
717 || (sizeof (ret) != value_size))
718 ret = -1;
719 }
720#endif /* HAVE_SYSCTLBYNAME */
721#if defined(HAVE_SYSCTL) && \
722 defined(HAS_DECL_CTL_HW) && \
723 defined(HAS_DECL_HW_NCPUONLINE)
724 if (0 >= ret)
725 {
726 /* OpenBSD, NetBSD: The number of online CPUs */
727 int mib[2] = {CTL_HW, HW_NCPUONLINE};
728 size_t value_size = sizeof (ret);
729 if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
730 || (sizeof (ret) != value_size))
731 ret = -1;
732 }
733#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPUONLINE */
734#if defined(HAVE_SYSCTL) && \
735 defined(HAS_DECL_CTL_HW) && \
736 defined(HAS_DECL_HW_AVAILCPU)
737 if (0 >= ret)
738 {
739 /* Darwin: The MIB name for "hw.activecpu" */
740 int mib[2] = {CTL_HW, HW_AVAILCPU};
741 size_t value_size = sizeof (ret);
742 if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
743 || (sizeof (ret) != value_size))
744 ret = -1;
745 }
746#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_AVAILCPU */
747#endif /* ! __linux__ */
748 if (0 >= ret)
749 return -1;
750 return ret;
751}
752
753
765static int
767{
768 int ret = -1;
769 /* Do not use sysctl() function on GNU/Linux even if
770 sysctl() is available */
771#ifndef __linux__
772#ifdef HAVE_SYSCTLBYNAME
773 if (0 >= ret)
774 {
775 size_t value_size = sizeof (ret);
776 /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */
777 if ((0 != sysctlbyname ("hw.ncpu", &ret, &value_size,
778 NULL, 0))
779 || (sizeof (ret) != value_size))
780 ret = -1;
781 }
782#endif /* HAVE_SYSCTLBYNAME */
783#if defined(HAVE_SYSCTL) && \
784 defined(HAS_DECL_CTL_HW) && \
785 defined(HAS_DECL_HW_NCPU)
786 if (0 >= ret)
787 {
788 /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */
789 int mib[2] = {CTL_HW, HW_NCPU};
790 size_t value_size = sizeof (ret);
791 if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
792 || (sizeof (ret) != value_size))
793 ret = -1;
794 }
795#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPU */
796#endif /* ! __linux__ */
797 if (0 >= ret)
798 return -1;
799 return ret;
800}
801
802
811static int
813{
814 int ret = -1;
815#if defined(HAVE_SYSCONF) && \
816 (defined(HAS_DECL__SC_NPROCESSORS_ONLN) || defined(HAS_DECL__SC_NPROC_ONLN))
817 long value = -1;
818#ifdef HAS_DECL__SC_NPROCESSORS_ONLN
819 if (0 >= value)
820 value = sysconf (_SC_NPROCESSORS_ONLN);
821#endif /* HAS_DECL__SC_NPROCESSORS_ONLN */
822#ifdef HAS_DECL__SC_NPROC_ONLN
823 if (0 >= value)
824 value = sysconf (_SC_NPROC_ONLN);
825#endif /* HAS_DECL__SC_NPROC_ONLN */
826 if (0 >= value)
827 return -1;
828 ret = (int) value;
829 if ((long) ret != value)
830 return -1; /* Overflow */
831#endif /* HAVE_SYSCONF &&
832 (HAS_DECL__SC_NPROCESSORS_ONLN || HAS_DECL__SC_NPROC_ONLN) */
833 return ret;
834}
835
836
847static int
849{
850 int ret = -1;
851#if defined(HAVE_SYSCONF) && \
852 (defined(HAS_DECL__SC_CRAY_NCPU) || defined(HAS_DECL__SC_NPROCESSORS_CONF))
853 long value = -1;
854#ifdef HAS_DECL__SC_CRAY_NCPU
855 if (0 >= value)
856 value = sysconf (_SC_CRAY_NCPU);
857#endif /* HAS_DECL__SC_CRAY_NCPU */
858#ifdef HAS_DECL__SC_NPROCESSORS_CONF
859 if (0 >= value)
860 value = sysconf (_SC_NPROCESSORS_CONF);
861#endif /* HAS_DECL__SC_NPROCESSORS_CONF */
862 if (0 >= value)
863 return -1;
864 ret = (int) value;
865 if ((long) ret != value)
866 return -1; /* Overflow */
867#endif /* HAVE_SYSCONF &&
868 (HAS_DECL__SC_CRAY_NCPU || HAS_DECL__SC_NPROCESSORS_CONF) */
869 return ret;
870}
871
872
880int
882{
883 int res;
884
885 /* Try specialised APIs first */
887 if (0 < res)
888 return res;
889
890 /* Try sysctl*(). This is typically a direct interface to
891 kernel values. */
893 if (0 < res)
894 return res;
895
896 /* Try sysconf() as the last resort as this is a generic interface
897 which can be implemented by parsing system files. */
899#if ! defined(__linux__) && ! defined(__GLIBC__)
900 if (0 < res)
901 return res;
902#else /* __linux__ || __GLIBC__ */
903 if (2 < res)
904 return res;
905 if (0 < res)
906 {
907 /* '1' or '2' could a be fallback number.
908 * See get_nprocs_fallback() in glibc
909 sysdeps/unix/sysv/linux/getsysstats.c */
910
911 int proc_cpu_count;
912
913 proc_cpu_count = mhd_tool_get_proc_cpu_count ();
914 if (proc_cpu_count == res)
915 {
916 /* The detected number of CPUs available for the process
917 is equal to the detected number of system CPUs.
918 Assume detected number is correct. */
919 return res;
920 }
921 }
922#endif /* __linux__ || __GLIBC__ */
923
924 /* Try available fallbacks */
925
927 if (0 < res)
928 return res;
929
931#if ! defined(__linux__) && ! defined(__GLIBC__)
932 if (0 < res)
933 return res;
934#else /* __linux__ || __GLIBC__ */
935 if (2 < res)
936 return res;
937#endif /* __linux__ || __GLIBC__ */
938
939 return -1; /* Cannot detect */
940}
#define NULL
additional automatic macros for MHD_config.h
int mhd_tool_get_system_cpu_count(void)
static int mhd_tool_get_proc_cpu_count_sched_getaffinity_(void)
static int mhd_tool_get_sys_cpu_count_sysconf_(void)
static int mhd_tool_get_proc_cpu_count_sched_getaffinity_np_(void)
static int mhd_tool_get_proc_cpu_count_cpuset_getaffinity_(void)
static int mhd_tool_get_sys_cpu_count_sysconf_fallback_(void)
static int mhd_tool_get_sys_cpu_count_sysctl_fallback_(void)
static int mhd_tool_get_sys_cpu_count_special_api_(void)
static int mhd_tool_get_sys_cpu_count_sysctl_(void)
int mhd_tool_get_proc_cpu_count(void)
#define CPU_SETSIZE_SAFE
static int mhd_tool_get_proc_cpu_count_w32_(void)
#define CPU_SETSIZE
Declaration of functions to detect the number of available CPU cores.