5757#include <errno.h>
5858#if defined(HAVE_UNSHARE ) || defined(HAVE_SCHED_SETAFFINITY ) || defined(HAVE_SCHED_GETCPU )
5959#include <sched.h>
60+ #if defined(__linux__ ) && defined(CPU_ALLOC )
61+ #define PCNTL_CPUSET_DYNAMIC 1
62+ typedef cpu_set_t * PCNTL_CPUSET_T ;
63+ #define PCNTL_CPUSET (mask ) (mask)
64+ #define PCNTL_CPUSET_SIZE (mask , sz ) (sz)
65+ #define PCNTL_CPU_ISSET (i , mask , sz ) CPU_ISSET_S(i, sz, mask)
66+ #define PCNTL_CPU_SET (i , mask , sz ) CPU_SET_S(i, sz, mask)
67+ #define PCNTL_CPU_ALLOC (mask , sz , maxcpus ) \
68+ do { \
69+ (sz) = MAX(CPU_ALLOC_SIZE(maxcpus), sizeof(cpu_set_t)); \
70+ (mask) = ecalloc(1, (sz)); \
71+ } while (0)
72+ #define PCNTL_CPU_DESTROY (mask ) efree(mask)
73+ #else
6074#if defined(__FreeBSD__ )
6175#include <sys/types.h>
6276#include <sys/cpuset.h>
6377typedef cpuset_t cpu_set_t ;
6478#endif
65- #define PCNTL_CPUSET (mask ) &mask
66- #define PCNTL_CPUSET_SIZE (mask ) sizeof(mask)
67- #define PCNTL_CPU_ISSET (i , mask ) CPU_ISSET(i, &mask)
68- #define PCNTL_CPU_SET (i , mask ) CPU_SET(i, &mask)
69- #define PCNTL_CPU_ZERO (mask ) CPU_ZERO(&mask)
79+ typedef cpu_set_t PCNTL_CPUSET_T ;
80+ #define PCNTL_CPUSET (mask ) (&(mask))
81+ #define PCNTL_CPUSET_SIZE (mask , sz ) (sz)
82+ #define PCNTL_CPU_ISSET (i , mask , sz ) CPU_ISSET(i, &(mask))
83+ #define PCNTL_CPU_SET (i , mask , sz ) CPU_SET(i, &(mask))
84+ #define PCNTL_CPU_ALLOC (mask , sz , maxcpus ) \
85+ do { \
86+ CPU_ZERO(&(mask)); \
87+ (sz) = sizeof(mask); \
88+ } while (0)
7089 #define PCNTL_CPU_DESTROY (mask ) ((void)0)
90+ #endif
7191#elif defined(__NetBSD__ )
7292#include <sys/syscall.h>
7393#include <sched.h>
74- typedef cpuset_t * cpu_set_t ;
94+ typedef cpuset_t * PCNTL_CPUSET_T ;
7595 #define sched_getaffinity (p , c , m ) syscall(SYS__sched_getaffinity, p, 0, c, m)
7696 #define sched_setaffinity (p , c , m ) syscall(SYS__sched_setaffinity, p, 0, c, m)
77- #define PCNTL_CPUSET (mask ) mask
78- #define PCNTL_CPUSET_SIZE (mask ) cpuset_size(mask )
79- #define PCNTL_CPU_ISSET (i , mask ) cpuset_isset((cpuid_t)i, mask)
80- #define PCNTL_CPU_SET (i , mask ) cpuset_set((cpuid_t)i, mask)
81- #define PCNTL_CPU_ZERO (mask ) \
97+ #define PCNTL_CPUSET (mask ) ( mask)
98+ #define PCNTL_CPUSET_SIZE (mask , sz ) (sz )
99+ #define PCNTL_CPU_ISSET (i , mask , sz ) cpuset_isset((cpuid_t)i, mask)
100+ #define PCNTL_CPU_SET (i , mask , sz ) cpuset_set((cpuid_t)i, mask)
101+ #define PCNTL_CPU_ALLOC (mask , sz , maxcpus ) \
82102 do { \
83103 mask = cpuset_create(); \
84104 if (UNEXPECTED(!mask)) { \
85105 php_error_docref(NULL, E_WARNING, "cpuset_create: Insufficient memory"); \
86106 RETURN_FALSE; \
87107 } \
88108 cpuset_zero(mask); \
109+ (sz) = cpuset_size(mask); \
89110 } while(0)
90111 #define PCNTL_CPU_DESTROY (mask ) cpuset_destroy(mask)
91112 #define HAVE_SCHED_SETAFFINITY 1
92113#elif defined(HAVE_PSET_BIND )
93114#include <sys/pset.h>
94- typedef psetid_t cpu_set_t ;
95- #define sched_getaffinity (p , c , m ) pset_bind(PS_QUERY, P_PID, p, &m)
96- #define sched_setaffinity (p , c , m ) pset_bind(m, P_PID, (p <= 0 ? getpid() : p), NULL)
115+ typedef psetid_t PCNTL_CPUSET_T ;
116+ #define sched_getaffinity (p , c , m ) ((void)(c), pset_bind(PS_QUERY, P_PID, p, &m) )
117+ #define sched_setaffinity (p , c , m ) ((void)(c), pset_bind(m, P_PID, (p <= 0 ? getpid() : p), NULL) )
97118 #define PCNTL_CPUSET (mask ) mask
98- #define PCNTL_CPU_ISSET (i , mask ) (pset_assign(PS_QUERY, (processorid_t)i, &query) == 0 && query == mask)
99- #define PCNTL_CPU_SET (i , mask ) pset_assign(mask, (processorid_t)i, NULL)
100- #define PCNTL_CPU_ZERO (mask ) \
119+ #define PCNTL_CPUSET_SIZE (mask , sz ) (sz)
120+ #define PCNTL_CPU_ISSET (i , mask , sz ) (pset_assign(PS_QUERY, (processorid_t)i, &query) == 0 && query == mask)
121+ #define PCNTL_CPU_SET (i , mask , sz ) pset_assign(mask, (processorid_t)i, NULL)
122+ #define PCNTL_CPU_ALLOC (mask , sz , maxcpus ) \
101123 psetid_t query; \
102124 do { \
103125 if (UNEXPECTED(pset_create(&mask) != 0)) { \
104126 php_error_docref(NULL, E_WARNING, "pset_create: %s", strerror(errno)); \
105127 RETURN_FALSE; \
106128 } \
129+ (sz) = sizeof(mask); \
107130 } while (0)
108131 #define PCNTL_CPU_DESTROY (mask ) \
109132 do { \
@@ -1678,11 +1701,46 @@ PHP_FUNCTION(pcntl_setns)
16781701#endif
16791702
16801703#ifdef HAVE_SCHED_SETAFFINITY
1704+ static zend_long pcntl_cpu_count (void )
1705+ {
1706+ errno = 0 ;
1707+ zend_long maxcpus = sysconf (_SC_NPROCESSORS_CONF );
1708+ if (UNEXPECTED (maxcpus < 0 )) {
1709+ PCNTL_G (last_error ) = errno ? errno : EINVAL ;
1710+ php_error_docref (NULL , E_WARNING , "Cannot determine the number of cpus" );
1711+ }
1712+
1713+ return maxcpus ;
1714+ }
1715+
1716+ #ifdef PCNTL_CPUSET_DYNAMIC
1717+ #define PCNTL_CPUSET_MAX_SIZE (1024 * 1024)
1718+
1719+ static bool pcntl_getaffinity (pid_t pid , PCNTL_CPUSET_T * mask , size_t * sz )
1720+ {
1721+ while (sched_getaffinity (pid , * sz , * mask ) != 0 ) {
1722+ if (errno != EINVAL || * sz >= PCNTL_CPUSET_MAX_SIZE ) {
1723+ return false;
1724+ }
1725+
1726+ efree (* mask );
1727+ * sz *= 2 ;
1728+ * mask = ecalloc (1 , * sz );
1729+ }
1730+
1731+ return true;
1732+ }
1733+ #else
1734+ # define pcntl_getaffinity (pid , mask , sz ) \
1735+ (sched_getaffinity(pid, PCNTL_CPUSET_SIZE(*(mask), *(sz)), PCNTL_CPUSET(*(mask))) == 0)
1736+ #endif
1737+
16811738PHP_FUNCTION (pcntl_getcpuaffinity )
16821739{
16831740 zend_long pid ;
16841741 bool pid_is_null = 1 ;
1685- cpu_set_t mask ;
1742+ PCNTL_CPUSET_T mask ;
1743+ size_t sz ;
16861744
16871745 ZEND_PARSE_PARAMETERS_START (0 , 1 )
16881746 Z_PARAM_OPTIONAL
@@ -1691,10 +1749,15 @@ PHP_FUNCTION(pcntl_getcpuaffinity)
16911749
16921750 // 0 == getpid in this context, we're just saving a syscall
16931751 pid = pid_is_null ? 0 : pid ;
1752+ zend_long maxcpus = pcntl_cpu_count ();
16941753
1695- PCNTL_CPU_ZERO (mask );
1754+ if (UNEXPECTED (maxcpus < 0 )) {
1755+ RETURN_FALSE ;
1756+ }
16961757
1697- if (sched_getaffinity (pid , PCNTL_CPUSET_SIZE (mask ), PCNTL_CPUSET (mask )) != 0 ) {
1758+ PCNTL_CPU_ALLOC (mask , sz , maxcpus );
1759+
1760+ if (!pcntl_getaffinity (pid , & mask , & sz )) {
16981761 PCNTL_CPU_DESTROY (mask );
16991762 PCNTL_G (last_error ) = errno ;
17001763 switch (errno ) {
@@ -1714,12 +1777,11 @@ PHP_FUNCTION(pcntl_getcpuaffinity)
17141777 RETURN_FALSE ;
17151778 }
17161779
1717- zend_ulong maxcpus = (zend_ulong )sysconf (_SC_NPROCESSORS_CONF );
17181780 array_init (return_value );
17191781 zend_hash_real_init_packed (Z_ARRVAL_P (return_value ));
17201782
1721- for (zend_ulong i = 0 ; i < maxcpus ; i ++ ) {
1722- if (PCNTL_CPU_ISSET (i , mask )) {
1783+ for (zend_long i = 0 ; i < maxcpus ; i ++ ) {
1784+ if (PCNTL_CPU_ISSET (i , mask , sz )) {
17231785 add_next_index_long (return_value , i );
17241786 }
17251787 }
@@ -1730,8 +1792,9 @@ PHP_FUNCTION(pcntl_setcpuaffinity)
17301792{
17311793 zend_long pid ;
17321794 bool pid_is_null = 1 ;
1733- cpu_set_t mask ;
1795+ PCNTL_CPUSET_T mask ;
17341796 zval * hmask = NULL , * ncpu ;
1797+ size_t sz ;
17351798
17361799 ZEND_PARSE_PARAMETERS_START (0 , 2 )
17371800 Z_PARAM_OPTIONAL
@@ -1747,8 +1810,13 @@ PHP_FUNCTION(pcntl_setcpuaffinity)
17471810
17481811 // 0 == getpid in this context, we're just saving a syscall
17491812 pid = pid_is_null ? 0 : pid ;
1750- zend_long maxcpus = sysconf (_SC_NPROCESSORS_CONF );
1751- PCNTL_CPU_ZERO (mask );
1813+ zend_long maxcpus = pcntl_cpu_count ();
1814+
1815+ if (UNEXPECTED (maxcpus < 0 )) {
1816+ RETURN_FALSE ;
1817+ }
1818+
1819+ PCNTL_CPU_ALLOC (mask , sz , maxcpus );
17521820
17531821 ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (hmask ), ncpu ) {
17541822 ZVAL_DEREF (ncpu );
@@ -1773,17 +1841,17 @@ PHP_FUNCTION(pcntl_setcpuaffinity)
17731841 }
17741842
17751843 if (cpu < 0 || cpu >= maxcpus ) {
1776- zend_argument_value_error (2 , "cpu id must be between 0 and " ZEND_ULONG_FMT " (" ZEND_LONG_FMT ")" , maxcpus , cpu );
1844+ zend_argument_value_error (2 , "cpu id must be between 0 and " ZEND_LONG_FMT " (" ZEND_LONG_FMT ")" , maxcpus , cpu );
17771845 PCNTL_CPU_DESTROY (mask );
17781846 RETURN_THROWS ();
17791847 }
17801848
1781- if (!PCNTL_CPU_ISSET (cpu , mask )) {
1782- PCNTL_CPU_SET (cpu , mask );
1849+ if (!PCNTL_CPU_ISSET (cpu , mask , sz )) {
1850+ PCNTL_CPU_SET (cpu , mask , sz );
17831851 }
17841852 } ZEND_HASH_FOREACH_END ();
17851853
1786- if (sched_setaffinity (pid , PCNTL_CPUSET_SIZE (mask ), PCNTL_CPUSET (mask )) != 0 ) {
1854+ if (sched_setaffinity (pid , PCNTL_CPUSET_SIZE (mask , sz ), PCNTL_CPUSET (mask )) != 0 ) {
17871855 PCNTL_CPU_DESTROY (mask );
17881856 PCNTL_G (last_error ) = errno ;
17891857 switch (errno ) {
0 commit comments