Skip to content

Commit bdab6c1

Browse files
committed
ext/pcntl: pcntl_getqos_class/pcntl_setqos_class addition.
Introducting macOs Quality Of Service through those two calls. on macOs arm64/M*, there is no concept of individual cores, thus the old thread policy for cpu affinity does not work here. Instead, the user can apply to the current process the level of performance/energy consumption they wish from the highest QOS_CLASS_USER_INTERACTIVE to QOS_CLASS_BACKGROUND.
1 parent 843946a commit bdab6c1

File tree

5 files changed

+150
-2
lines changed

5 files changed

+150
-2
lines changed

ext/pcntl/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if test "$PHP_PCNTL" != "no"; then
77
AC_CHECK_FUNCS([fork], [], [AC_MSG_ERROR([pcntl: fork() not supported by this platform])])
88
AC_CHECK_FUNCS([waitpid], [], [AC_MSG_ERROR([pcntl: waitpid() not supported by this platform])])
99
AC_CHECK_FUNCS([sigaction], [], [AC_MSG_ERROR([pcntl: sigaction() not supported by this platform])])
10-
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx pidfd_open sched_setaffinity])
10+
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx pidfd_open sched_setaffinity pthread_set_qos_class_self_np])
1111

1212
dnl if unsupported, -1 means automatically ENOSYS in this context
1313
AC_MSG_CHECKING([if sched_getcpu is supported])

ext/pcntl/pcntl.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ typedef cpuset_t cpu_set_t;
5151
#endif
5252
#endif
5353

54+
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
55+
#include <pthread/qos.h>
56+
#endif
57+
5458
#ifdef HAVE_PIDFD_OPEN
5559
#include <sys/syscall.h>
5660
#endif
@@ -1622,6 +1626,43 @@ PHP_FUNCTION(pcntl_getcpu)
16221626
}
16231627
#endif
16241628

1629+
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
1630+
PHP_FUNCTION(pcntl_getqos_class)
1631+
{
1632+
qos_class_t qos_class;
1633+
1634+
ZEND_PARSE_PARAMETERS_NONE();
1635+
1636+
if (UNEXPECTED(pthread_get_qos_class_np(pthread_self(), &qos_class, NULL) != 0))
1637+
{
1638+
// unlikely unless an external tool set the QOS class with a wrong value
1639+
PCNTL_G(last_error) = errno;
1640+
zend_value_error("invalid QOS class %u", qos_class);
1641+
RETURN_THROWS();
1642+
}
1643+
1644+
RETURN_LONG((zend_long)qos_class);
1645+
}
1646+
1647+
PHP_FUNCTION(pcntl_setqos_class)
1648+
{
1649+
zend_long qos_class = QOS_CLASS_DEFAULT;
1650+
1651+
ZEND_PARSE_PARAMETERS_START(1, 1)
1652+
Z_PARAM_LONG(qos_class)
1653+
ZEND_PARSE_PARAMETERS_END();
1654+
1655+
if (pthread_set_qos_class_self_np((qos_class_t)qos_class, 0) != 0)
1656+
{
1657+
PCNTL_G(last_error) = errno;
1658+
zend_argument_value_error(1, "must be between QOS_CLASS_USER_INTERACTIVE and QOS_CLASS_BLACKGROUND");
1659+
RETURN_THROWS();
1660+
}
1661+
1662+
RETURN_TRUE;
1663+
}
1664+
#endif
1665+
16251666
static void pcntl_interrupt_function(zend_execute_data *execute_data)
16261667
{
16271668
pcntl_signal_dispatch();

ext/pcntl/pcntl.stub.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,39 @@
905905
const PCNTL_ECAPMODE = UNKNOWN;
906906
#endif
907907

908+
#ifdef HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP
909+
/**
910+
* @var int
911+
* @cvalue QOS_CLASS_USER_INTERACTIVE
912+
*/
913+
const QOS_CLASS_USER_INTERACTIVE = UNKNOWN;
914+
/**
915+
* @var int
916+
* @cvalue QOS_CLASS_USER_INITIATED
917+
*/
918+
const QOS_CLASS_USER_INITIATED = UNKNOWN;
919+
/**
920+
* @var int
921+
* @cvalue QOS_CLASS_DEFAULT
922+
*/
923+
const QOS_CLASS_DEFAULT = UNKNOWN;
924+
/**
925+
* @var int
926+
* @cvalue QOS_CLASS_UTILITY
927+
*/
928+
const QOS_CLASS_UTILITY = UNKNOWN;
929+
/**
930+
* @var int
931+
* @cvalue QOS_CLASS_BACKGROUND
932+
*/
933+
const QOS_CLASS_BACKGROUND = UNKNOWN;
934+
/**
935+
* @var int
936+
* @cvalue QOS_CLASS_UNSPECIFIED
937+
*/
938+
const QOS_CLASS_UNSPECIFIED = UNKNOWN;
939+
#endif
940+
908941
function pcntl_fork(): int {}
909942

910943
/**
@@ -1003,3 +1036,8 @@ function pcntl_setcpuaffinity(?int $process_id = null, array $cpu_ids = []): boo
10031036
#ifdef HAVE_SCHED_GETCPU
10041037
function pcntl_getcpu(): int {}
10051038
#endif
1039+
1040+
#ifdef HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP
1041+
function pcntl_getqos_class(): int {}
1042+
function pcntl_setqos_class(int $qos_class = QOS_CLASS_DEFAULT): bool {}
1043+
#endif

ext/pcntl/pcntl_arginfo.h

Lines changed: 42 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/pcntl/tests/pcntl_qosclass.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
pcntl_getqos_class()/pcntl_setqos_class()
3+
--EXTENSIONS--
4+
pcntl
5+
--SKIPIF--
6+
<?php
7+
if (!function_exists("pcntl_getqos_class")) die("skip pcntl_getqos_class() is not available");
8+
if (getenv('SKIP_REPEAT')) die("skip Not repeatable");
9+
?>
10+
--FILE--
11+
<?php
12+
var_dump(pcntl_setqos_class(QOS_CLASS_DEFAULT));
13+
var_dump(QOS_CLASS_DEFAULT === pcntl_getqos_class());
14+
15+
try {
16+
pcntl_setqos_class(QOS_CLASS_UNSPECIFIED);
17+
} catch (\ValueError $e) {
18+
echo $e->getMessage() . PHP_EOL;
19+
}
20+
var_dump(pcntl_setqos_class(QOS_CLASS_BACKGROUND));
21+
var_dump(QOS_CLASS_BACKGROUND === pcntl_getqos_class());
22+
?>
23+
--EXPECT--
24+
bool(true)
25+
bool(true)
26+
pcntl_setqos_class(): Argument #1 ($qos_class) must be between QOS_CLASS_USER_INTERACTIVE and QOS_CLASS_BLACKGROUND
27+
bool(true)
28+
bool(true)

0 commit comments

Comments
 (0)