X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fnproc.c;h=6fdaea0d09aa4ff2337cea6b7ee456b09775eca0;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=af4da75d188f775c6852ae62de7e2eedf2b00097;hpb=b2e2010c7c902235b5efb5bd3c6529f61b093aa4;p=gnulib.git diff --git a/lib/nproc.c b/lib/nproc.c index af4da75d1..6fdaea0d0 100644 --- a/lib/nproc.c +++ b/lib/nproc.c @@ -1,6 +1,6 @@ /* Detect the number of processors. - Copyright (C) 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,8 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program; if not, see . */ /* Written by Glen Lenker and Bruno Haible. */ @@ -24,7 +23,7 @@ #include #include -#if HAVE_PTHREAD_AFFINITY_NP && 0 +#if HAVE_PTHREAD_GETAFFINITY_NP && 0 # include # include #endif @@ -59,6 +58,144 @@ #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +/* Return the number of processors available to the current process, based + on a modern system call that returns the "affinity" between the current + process and each CPU. Return 0 if unknown or if such a system call does + not exist. */ +static unsigned long +num_processors_via_affinity_mask (void) +{ + /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np, + but with different APIs. Also it requires linking with -lpthread. + Therefore this code is not enabled. + glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has + sched_getaffinity_np. */ +#if HAVE_PTHREAD_GETAFFINITY_NP && defined __GLIBC__ && 0 + { + cpu_set_t set; + + if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0) + { + unsigned long count; + +# ifdef CPU_COUNT + /* glibc >= 2.6 has the CPU_COUNT macro. */ + count = CPU_COUNT (&set); +# else + size_t i; + + count = 0; + for (i = 0; i < CPU_SETSIZE; i++) + if (CPU_ISSET (i, &set)) + count++; +# endif + if (count > 0) + return count; + } + } +#elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0 + { + cpuset_t *set; + + set = cpuset_create (); + if (set != NULL) + { + unsigned long count = 0; + + if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set) + == 0) + { + cpuid_t i; + + for (i = 0;; i++) + { + int ret = cpuset_isset (i, set); + if (ret < 0) + break; + if (ret > 0) + count++; + } + } + cpuset_destroy (set); + if (count > 0) + return count; + } + } +#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ + { + cpu_set_t set; + + if (sched_getaffinity (0, sizeof (set), &set) == 0) + { + unsigned long count; + +# ifdef CPU_COUNT + /* glibc >= 2.6 has the CPU_COUNT macro. */ + count = CPU_COUNT (&set); +# else + size_t i; + + count = 0; + for (i = 0; i < CPU_SETSIZE; i++) + if (CPU_ISSET (i, &set)) + count++; +# endif + if (count > 0) + return count; + } + } +#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */ + { + cpuset_t *set; + + set = cpuset_create (); + if (set != NULL) + { + unsigned long count = 0; + + if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0) + { + cpuid_t i; + + for (i = 0;; i++) + { + int ret = cpuset_isset (i, set); + if (ret < 0) + break; + if (ret > 0) + count++; + } + } + cpuset_destroy (set); + if (count > 0) + return count; + } + } +#endif + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + { /* This works on native Windows platforms. */ + DWORD_PTR process_mask; + DWORD_PTR system_mask; + + if (GetProcessAffinityMask (GetCurrentProcess (), + &process_mask, &system_mask)) + { + DWORD_PTR mask = process_mask; + unsigned long count = 0; + + for (; mask != 0; mask = mask >> 1) + if (mask & 1) + count++; + if (count > 0) + return count; + } + } +#endif + + return 0; +} + unsigned long int num_processors (enum nproc_query query) { @@ -94,138 +231,32 @@ num_processors (enum nproc_query query) } /* Here query is one of NPROC_ALL, NPROC_CURRENT. */ - if (query == NPROC_CURRENT) - { - /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np, - but with different APIs. Also it requires linking with -lpthread. - Therefore this code is not enabled. - glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has - sched_getaffinity_np. */ -#if HAVE_PTHREAD_AFFINITY_NP && defined __GLIBC__ && 0 - { - cpu_set_t set; - - if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0) - { - unsigned long count; - -# ifdef CPU_COUNT - /* glibc >= 2.6 has the CPU_COUNT macro. */ - count = CPU_COUNT (&set); -# else - size_t i; - - count = 0; - for (i = 0; i < CPU_SETSIZE; i++) - if (CPU_ISSET (i, &set)) - count++; -# endif - if (count > 0) - return count; - } - } -#elif HAVE_PTHREAD_AFFINITY_NP && defined __NetBSD__ && 0 - { - cpuset_t *set; - - set = cpuset_create (); - if (set != NULL) - { - unsigned long count = 0; + /* On systems with a modern affinity mask system call, we have + sysconf (_SC_NPROCESSORS_CONF) + >= sysconf (_SC_NPROCESSORS_ONLN) + >= num_processors_via_affinity_mask () + The first number is the number of CPUs configured in the system. + The second number is the number of CPUs available to the scheduler. + The third number is the number of CPUs available to the current process. - if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set) - == 0) - { - cpuid_t i; - - for (i = 0;; i++) - { - int ret = cpuset_isset (i, set); - if (ret < 0) - break; - if (ret > 0) - count++; - } - } - cpuset_destroy (set); - if (count > 0) - return count; - } - } -#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ - { - cpu_set_t set; + Note! On Linux systems with glibc, the first and second number come from + the /sys and /proc file systems (see + glibc/sysdeps/unix/sysv/linux/getsysstats.c). + In some situations these file systems are not mounted, and the sysconf + call returns 1, which does not reflect the reality. */ - if (sched_getaffinity (0, sizeof (set), &set) == 0) - { - unsigned long count; - -# ifdef CPU_COUNT - /* glibc >= 2.6 has the CPU_COUNT macro. */ - count = CPU_COUNT (&set); -# else - size_t i; - - count = 0; - for (i = 0; i < CPU_SETSIZE; i++) - if (CPU_ISSET (i, &set)) - count++; -# endif - if (count > 0) - return count; - } - } -#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */ + if (query == NPROC_CURRENT) + { + /* Try the modern affinity mask system call. */ { - cpuset_t *set; - - set = cpuset_create (); - if (set != NULL) - { - unsigned long count = 0; - - if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0) - { - cpuid_t i; - - for (i = 0;; i++) - { - int ret = cpuset_isset (i, set); - if (ret < 0) - break; - if (ret > 0) - count++; - } - } - cpuset_destroy (set); - if (count > 0) - return count; - } - } -#endif + unsigned long nprocs = num_processors_via_affinity_mask (); -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ - { /* This works on native Windows platforms. */ - DWORD_PTR process_mask; - DWORD_PTR system_mask; - - if (GetProcessAffinityMask (GetCurrentProcess (), - &process_mask, &system_mask)) - { - DWORD_PTR mask = process_mask; - unsigned long count = 0; - - for (; mask != 0; mask = mask >> 1) - if (mask & 1) - count++; - if (count > 0) - return count; - } + if (nprocs > 0) + return nprocs; } -#endif #if defined _SC_NPROCESSORS_ONLN - { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris, + { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris, Cygwin, Haiku. */ long int nprocs = sysconf (_SC_NPROCESSORS_ONLN); if (nprocs > 0) @@ -236,9 +267,25 @@ num_processors (enum nproc_query query) else /* query == NPROC_ALL */ { #if defined _SC_NPROCESSORS_CONF - { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris, + { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris, Cygwin, Haiku. */ long int nprocs = sysconf (_SC_NPROCESSORS_CONF); + +# if __GLIBC__ >= 2 && defined __linux__ + /* On Linux systems with glibc, this information comes from the /sys and + /proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c). + In some situations these file systems are not mounted, and the + sysconf call returns 1. But we wish to guarantee that + num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */ + if (nprocs == 1) + { + unsigned long nprocs_current = num_processors_via_affinity_mask (); + + if (nprocs_current > 0) + nprocs = nprocs_current; + } +# endif + if (nprocs > 0) return nprocs; } @@ -285,7 +332,7 @@ num_processors (enum nproc_query query) NPROC_CURRENT and NPROC_ALL. */ #if HAVE_SYSCTL && defined HW_NCPU - { /* This works on MacOS X, FreeBSD, NetBSD, OpenBSD. */ + { /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD. */ int nprocs; size_t len = sizeof (nprocs); static int mib[2] = { CTL_HW, HW_NCPU };