GNU libmicrohttpd  1.0.1
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 
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 #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 
119 static int
121 
128 static 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 
191 static 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 
258 static 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 
323 static 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 
523 int
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 
568 static 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 
667 static 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 
765 static 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 
811 static 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 
847 static 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 
880 int
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
Definition: reason_phrase.c:30
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.