1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/pcntl: Added rusage parameter to pcntl_waitid

This functionality is not part of the POSIX interface.

- On FreeBSD, the wait6 system call provides it
- On Linux, the raw waitid system call provides it (glibc does not)

close GH-15921
This commit is contained in:
Vladimir Vrzić
2024-09-16 17:59:40 +02:00
committed by David Carlier
parent ca49a7bec2
commit aea3ade74f
8 changed files with 137 additions and 11 deletions

3
NEWS
View File

@@ -134,6 +134,9 @@ PHP NEWS
- Output:
. Fixed calculation of aligned buffer size. (cmb)
- PCNTL:
. Extend pcntl_waitid with rusage parameter. (vrza)
- PCRE:
. Upgraded to pre2lib from 10.44 to 10.45. (nielsdos)
. Remove PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK from pcre compile options.

View File

@@ -289,6 +289,8 @@ PHP 8.5 UPGRADE NOTES
- PCNTL:
. pcntl_exec() now has a formal return type of false.
. pcntl_waitid() takes an additional resource_usage argument to
gather various platform specific metrics about the child process.
- PDO_PGSQL:
. PDO::pgsqlCopyFromArray also supports inputs as Iterable.

View File

@@ -25,6 +25,8 @@ if test "$PHP_PCNTL" != "no"; then
wait3
wait4
waitid
wait6
syscall
]))
AC_CHECK_FUNCS([WIFCONTINUED],,
@@ -43,6 +45,9 @@ if test "$PHP_PCNTL" != "no"; then
]),,,
[#include <sys/wait.h>])
AC_CHECK_DECLS([SYS_waitid],,,
[#include <sys/syscall.h>])
dnl if unsupported, -1 means automatically ENOSYS in this context
AC_CACHE_CHECK([if sched_getcpu is supported], [php_cv_func_sched_getcpu],
[AC_RUN_IFELSE([AC_LANG_SOURCE([

View File

@@ -125,7 +125,15 @@ typedef psetid_t cpu_set_t;
#include <pthread/qos.h>
#endif
#ifdef HAVE_PIDFD_OPEN
#if defined(__linux__) && defined(HAVE_DECL_SYS_WAITID) && HAVE_DECL_SYS_WAITID == 1 && defined(HAVE_SYSCALL)
#define HAVE_LINUX_RAW_SYSCALL_WAITID 1
#endif
#if defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
#include <unistd.h>
#endif
#if defined(HAVE_PIDFD_OPEN) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
#include <sys/syscall.h>
#endif
@@ -401,19 +409,49 @@ PHP_FUNCTION(pcntl_waitid)
bool id_is_null = 1;
zval *user_siginfo = NULL;
zend_long options = WEXITED;
zval *z_rusage = NULL;
ZEND_PARSE_PARAMETERS_START(0, 4)
siginfo_t siginfo;
int status;
ZEND_PARSE_PARAMETERS_START(0, 5)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(idtype)
Z_PARAM_LONG_OR_NULL(id, id_is_null)
Z_PARAM_ZVAL(user_siginfo)
Z_PARAM_LONG(options)
Z_PARAM_ZVAL(z_rusage)
ZEND_PARSE_PARAMETERS_END();
errno = 0;
siginfo_t siginfo;
memset(&siginfo, 0, sizeof(siginfo_t));
int status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
#if defined(HAVE_WAIT6) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
if (z_rusage) {
z_rusage = zend_try_array_init(z_rusage);
if (!z_rusage) {
RETURN_THROWS();
}
struct rusage rusage;
# if defined(HAVE_WAIT6) /* FreeBSD */
struct __wrusage wrusage;
memset(&wrusage, 0, sizeof(struct __wrusage));
pid_t pid = wait6((idtype_t) idtype, (id_t) id, &status, (int) options, &wrusage, &siginfo);
status = pid > 0 ? 0 : pid;
memcpy(&rusage, &wrusage.wru_self, sizeof(struct rusage));
# else /* Linux */
memset(&rusage, 0, sizeof(struct rusage));
status = syscall(SYS_waitid, (idtype_t) idtype, (id_t) id, &siginfo, (int) options, &rusage);
# endif
if (status == 0) {
PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
}
} else { /* POSIX */
status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
}
#else /* POSIX */
status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
#endif
if (status == -1) {
PCNTL_G(last_error) = errno;

View File

@@ -1006,8 +1006,11 @@ const PCNTL_ECAPMODE = UNKNOWN;
function pcntl_waitpid(int $process_id, &$status, int $flags = 0, &$resource_usage = []): int {}
#if defined (HAVE_WAITID) && defined (HAVE_POSIX_IDTYPES) && defined (HAVE_DECL_WEXITED) && HAVE_DECL_WEXITED == 1
/** @param array $info */
function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED): bool {}
/**
* @param array $info
* @param array $resource_usage
*/
function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED, &$resource_usage = []): bool {}
#endif
/**

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: c637fe2de641cfd8f0ff83a908ac59bf63a68e44 */
* Stub hash: 5e4b066d70fa264c7de3ba4b2113369c34c33e43 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_fork, 0, 0, IS_LONG, 0)
ZEND_END_ARG_INFO()
@@ -17,6 +17,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_waitid, 0, 0, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id, IS_LONG, 1, "null")
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, info, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "WEXITED")
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, resource_usage, "[]")
ZEND_END_ARG_INFO()
#endif

View File

@@ -26,10 +26,12 @@ if ($pid == -1) {
} else {
pcntl_signal(SIGUSR1, function ($_signo, $_siginfo) { exit(42); });
posix_kill(posix_getpid(), SIGSTOP);
pcntl_signal_dispatch();
sleep(42);
pcntl_signal_dispatch();
exit(6);
$nanoseconds = 100;
while (true) {
pcntl_signal_dispatch();
time_nanosleep(0, $nanoseconds);
$nanoseconds *= 2;
}
}
?>
--EXPECTF--

View File

@@ -0,0 +1,72 @@
--TEST--
pcntl_waitid() and rusage
--EXTENSIONS--
pcntl
posix
--SKIPIF--
<?php
if (!function_exists('pcntl_waitid')) die('skip pcntl_waitid unavailable');
if (!str_contains(PHP_OS, 'Linux') && !str_contains(PHP_OS, 'FreeBSD')) {
die('skip pcntl_waitid can return rusage only on FreeBSD and Linux');
}
?>
--FILE--
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('failed');
} else if ($pid) {
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WSTOPPED, $rusage));
var_dump($rusage['ru_utime.tv_sec']);
var_dump($rusage['ru_utime.tv_usec']);
$rusage = array(1,2,3);
posix_kill($pid, SIGCONT);
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WCONTINUED, $rusage));
var_dump($rusage['ru_utime.tv_sec']);
var_dump($rusage['ru_utime.tv_usec']);
posix_kill($pid, SIGUSR1);
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED, $rusage));
var_dump($rusage['ru_maxrss']);
var_dump($siginfo['status']);
$rusage = 'string';
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED | WNOHANG, $rusage));
var_dump(gettype($rusage));
var_dump(count($rusage));
$rusage = new stdClass;
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED | WNOHANG, $rusage));
var_dump(gettype($rusage));
var_dump(count($rusage));
fwrite(STDOUT, 'END' . PHP_EOL);
} else {
pcntl_signal(SIGUSR1, function ($_signo, $_siginfo) { exit(42); });
posix_kill(posix_getpid(), SIGSTOP);
$nanoseconds = 100;
while (true) {
pcntl_signal_dispatch();
time_nanosleep(0, $nanoseconds);
$nanoseconds *= 2;
}
}
?>
--EXPECTF--
bool(true)
int(%d)
int(%d)
bool(true)
int(%d)
int(%d)
bool(true)
int(%d)
int(42)
bool(false)
string(5) "array"
int(0)
bool(false)
string(5) "array"
int(0)
END