mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
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 QosClass::UserInteractive to QosClass::Background. Close GH-13945
This commit is contained in:
1
NEWS
1
NEWS
@@ -132,6 +132,7 @@ PHP NEWS
|
||||
. Updated pcntl_get_signal_handler signal id upper limit to be
|
||||
more in line with platforms limits. (David Carlier)
|
||||
. Added pcntl_getcpu for Linux/FreeBSD. (David Carlier)
|
||||
. Added pcntl_getqos_class/pcntl_setqos_class for macOs. (David Carlier)
|
||||
|
||||
- PCRE:
|
||||
. Upgrade bundled pcre2lib to version 10.43. (nielsdos)
|
||||
|
||||
@@ -475,6 +475,8 @@ PHP 8.4 UPGRADE NOTES
|
||||
. Added pcntl_getaffinity to get the cpu(s) bound to a process and
|
||||
pcntl_setaffinity to bind 1 or more cpus to a process.
|
||||
. Added pcntl_getcpu to get the cpu id from where the current process runs.
|
||||
. Added pcntl_getqos_class to get the QoS level (aka performance and related
|
||||
energy consumption) of the current process and pcntl_setqos_class to set it.
|
||||
|
||||
- Sodium:
|
||||
. Added the sodium_crypto_aead_aegis128l_*() and sodium_crypto_aead_aegis256l_*()
|
||||
@@ -582,6 +584,13 @@ PHP 8.4 UPGRADE NOTES
|
||||
. X509_PURPOSE_OCSP_HELPER.
|
||||
. X509_PURPOSE_TIMESTAMP_SIGN.
|
||||
|
||||
- PCNTL:
|
||||
. QosClass::Background (macOs only).
|
||||
. QosClass::Default (macOs only).
|
||||
. QosClass::UserInteractive (macOs only).
|
||||
. QosClass::UserInitiated (macOs only).
|
||||
. QosClass::Utility (macOs only).
|
||||
|
||||
- Standard:
|
||||
. PHP_ROUND_CEILING.
|
||||
. PHP_ROUND_FLOOR.
|
||||
|
||||
@@ -7,7 +7,7 @@ if test "$PHP_PCNTL" != "no"; then
|
||||
AC_CHECK_FUNCS([fork], [], [AC_MSG_ERROR([pcntl: fork() not supported by this platform])])
|
||||
AC_CHECK_FUNCS([waitpid], [], [AC_MSG_ERROR([pcntl: waitpid() not supported by this platform])])
|
||||
AC_CHECK_FUNCS([sigaction], [], [AC_MSG_ERROR([pcntl: sigaction() not supported by this platform])])
|
||||
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx pidfd_open sched_setaffinity])
|
||||
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx pidfd_open sched_setaffinity pthread_set_qos_class_self_np])
|
||||
|
||||
dnl if unsupported, -1 means automatically ENOSYS in this context
|
||||
AC_MSG_CHECKING([if sched_getcpu is supported])
|
||||
|
||||
@@ -51,6 +51,11 @@ typedef cpuset_t cpu_set_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
#include <pthread/qos.h>
|
||||
static zend_class_entry *QosClass_ce;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PIDFD_OPEN
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
@@ -65,10 +70,11 @@ typedef cpuset_t cpu_set_t;
|
||||
|
||||
#define LONG_CONST(c) (zend_long) c
|
||||
|
||||
#include "pcntl_arginfo.h"
|
||||
|
||||
#include "Zend/zend_enum.h"
|
||||
#include "Zend/zend_max_execution_timer.h"
|
||||
|
||||
#include "pcntl_arginfo.h"
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
|
||||
static PHP_GINIT_FUNCTION(pcntl);
|
||||
|
||||
@@ -136,6 +142,9 @@ PHP_RINIT_FUNCTION(pcntl)
|
||||
|
||||
PHP_MINIT_FUNCTION(pcntl)
|
||||
{
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
QosClass_ce = register_class_QosClass();
|
||||
#endif
|
||||
register_pcntl_symbols(module_number);
|
||||
orig_interrupt_function = zend_interrupt_function;
|
||||
zend_interrupt_function = pcntl_interrupt_function;
|
||||
@@ -1622,6 +1631,88 @@ PHP_FUNCTION(pcntl_getcpu)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
static qos_class_t qos_zval_to_lval(const zval *qos_obj)
|
||||
{
|
||||
qos_class_t qos_class = QOS_CLASS_DEFAULT;
|
||||
zend_string *entry = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(qos_obj)));
|
||||
|
||||
if (zend_string_equals_literal(entry, "UserInteractive")) {
|
||||
qos_class = QOS_CLASS_USER_INTERACTIVE;
|
||||
} else if (zend_string_equals_literal(entry, "UserInitiated")) {
|
||||
qos_class = QOS_CLASS_USER_INITIATED;
|
||||
} else if (zend_string_equals_literal(entry, "Utility")) {
|
||||
qos_class = QOS_CLASS_UTILITY;
|
||||
} else if (zend_string_equals_literal(entry, "Background")) {
|
||||
qos_class = QOS_CLASS_BACKGROUND;
|
||||
}
|
||||
|
||||
return qos_class;
|
||||
}
|
||||
|
||||
static zend_object *qos_lval_to_zval(qos_class_t qos_class)
|
||||
{
|
||||
const char *entryname;
|
||||
switch (qos_class)
|
||||
{
|
||||
case QOS_CLASS_USER_INTERACTIVE:
|
||||
entryname = "UserInteractive";
|
||||
break;
|
||||
case QOS_CLASS_USER_INITIATED:
|
||||
entryname = "UserInitiated";
|
||||
break;
|
||||
case QOS_CLASS_UTILITY:
|
||||
entryname = "Utility";
|
||||
break;
|
||||
case QOS_CLASS_BACKGROUND:
|
||||
entryname = "Background";
|
||||
break;
|
||||
case QOS_CLASS_DEFAULT:
|
||||
default:
|
||||
entryname = "Default";
|
||||
break;
|
||||
}
|
||||
|
||||
return zend_enum_get_case_cstr(QosClass_ce, entryname);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(pcntl_getqos_class)
|
||||
{
|
||||
qos_class_t qos_class;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
if (UNEXPECTED(pthread_get_qos_class_np(pthread_self(), &qos_class, NULL) != 0))
|
||||
{
|
||||
// unlikely unless an external tool set the QOS class with a wrong value
|
||||
PCNTL_G(last_error) = errno;
|
||||
zend_throw_error(NULL, "invalid QOS class %u", qos_class);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
RETURN_OBJ_COPY(qos_lval_to_zval(qos_class));
|
||||
}
|
||||
|
||||
PHP_FUNCTION(pcntl_setqos_class)
|
||||
{
|
||||
zval *qos_obj;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_OBJECT_OF_CLASS(qos_obj, QosClass_ce)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
qos_class_t qos_class = qos_zval_to_lval(qos_obj);
|
||||
|
||||
if (UNEXPECTED(pthread_set_qos_class_self_np((qos_class_t)qos_class, 0) != 0))
|
||||
{
|
||||
// unlikely, unless it is a new os issue, as we draw from the specified enum values
|
||||
PCNTL_G(last_error) = errno;
|
||||
zend_throw_error(NULL, "pcntl_setqos_class failed");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pcntl_interrupt_function(zend_execute_data *execute_data)
|
||||
{
|
||||
pcntl_signal_dispatch();
|
||||
|
||||
@@ -1003,3 +1003,17 @@ function pcntl_setcpuaffinity(?int $process_id = null, array $cpu_ids = []): boo
|
||||
#ifdef HAVE_SCHED_GETCPU
|
||||
function pcntl_getcpu(): int {}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP
|
||||
enum QosClass
|
||||
{
|
||||
case UserInteractive;
|
||||
case UserInitiated;
|
||||
case Default;
|
||||
case Utility;
|
||||
case Background;
|
||||
}
|
||||
|
||||
function pcntl_getqos_class(): QosClass {}
|
||||
function pcntl_setqos_class(QosClass $qos_class = QosClass::Default): void {}
|
||||
#endif
|
||||
|
||||
50
ext/pcntl/pcntl_arginfo.h
generated
50
ext/pcntl/pcntl_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 75eacf08a17e18c30fb2111bb742c36b18aa9ead */
|
||||
* Stub hash: 3e15bebb568e6e2031acbd932d6eefbd23984c83 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_fork, 0, 0, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -157,6 +157,17 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_getcpu, 0, 0, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_pcntl_getqos_class, 0, 0, QosClass, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_setqos_class, 0, 0, IS_VOID, 0)
|
||||
ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, qos_class, QosClass, 0, "QosClass::Default")
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif
|
||||
|
||||
ZEND_FUNCTION(pcntl_fork);
|
||||
ZEND_FUNCTION(pcntl_waitpid);
|
||||
ZEND_FUNCTION(pcntl_wait);
|
||||
@@ -213,6 +224,12 @@ ZEND_FUNCTION(pcntl_setcpuaffinity);
|
||||
#if defined(HAVE_SCHED_GETCPU)
|
||||
ZEND_FUNCTION(pcntl_getcpu);
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_FUNCTION(pcntl_getqos_class);
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_FUNCTION(pcntl_setqos_class);
|
||||
#endif
|
||||
|
||||
static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(pcntl_fork, arginfo_pcntl_fork)
|
||||
@@ -271,10 +288,22 @@ static const zend_function_entry ext_functions[] = {
|
||||
#endif
|
||||
#if defined(HAVE_SCHED_GETCPU)
|
||||
ZEND_FE(pcntl_getcpu, arginfo_pcntl_getcpu)
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_FE(pcntl_getqos_class, arginfo_pcntl_getqos_class)
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
ZEND_FE(pcntl_setqos_class, arginfo_pcntl_setqos_class)
|
||||
#endif
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
static const zend_function_entry class_QosClass_methods[] = {
|
||||
ZEND_FE_END
|
||||
};
|
||||
#endif
|
||||
|
||||
static void register_pcntl_symbols(int module_number)
|
||||
{
|
||||
#if defined(WNOHANG)
|
||||
@@ -628,3 +657,22 @@ static void register_pcntl_symbols(int module_number)
|
||||
REGISTER_LONG_CONSTANT("PCNTL_ECAPMODE", ECAPMODE, CONST_PERSISTENT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_PTHREAD_SET_QOS_CLASS_SELF_NP)
|
||||
static zend_class_entry *register_class_QosClass(void)
|
||||
{
|
||||
zend_class_entry *class_entry = zend_register_internal_enum("QosClass", IS_UNDEF, class_QosClass_methods);
|
||||
|
||||
zend_enum_add_case_cstr(class_entry, "UserInteractive", NULL);
|
||||
|
||||
zend_enum_add_case_cstr(class_entry, "UserInitiated", NULL);
|
||||
|
||||
zend_enum_add_case_cstr(class_entry, "Default", NULL);
|
||||
|
||||
zend_enum_add_case_cstr(class_entry, "Utility", NULL);
|
||||
|
||||
zend_enum_add_case_cstr(class_entry, "Background", NULL);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
#endif
|
||||
|
||||
19
ext/pcntl/tests/pcntl_qosclass.phpt
Normal file
19
ext/pcntl/tests/pcntl_qosclass.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
pcntl_getqos_class()/pcntl_setqos_class()
|
||||
--EXTENSIONS--
|
||||
pcntl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists("pcntl_getqos_class")) die("skip pcntl_getqos_class() is not available");
|
||||
if (getenv('SKIP_REPEAT')) die("skip Not repeatable");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
pcntl_setqos_class(QosClass::Default);
|
||||
var_dump(QosClass::Default === pcntl_getqos_class());
|
||||
pcntl_setqos_class(QosClass::Background);
|
||||
var_dump(QosClass::Background == pcntl_getqos_class());
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
||||
Reference in New Issue
Block a user