Skip to content

Commit b6951da

Browse files
committed
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)
1 parent 5fa0823 commit b6951da

File tree

5 files changed

+119
-7
lines changed

5 files changed

+119
-7
lines changed

ext/pcntl/config.m4

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ if test "$PHP_PCNTL" != "no"; then
2525
wait3
2626
wait4
2727
waitid
28+
wait6
29+
syscall
2830
]))
2931

3032
AC_CHECK_FUNCS([WIFCONTINUED],,
@@ -43,6 +45,9 @@ if test "$PHP_PCNTL" != "no"; then
4345
]),,,
4446
[#include <sys/wait.h>])
4547

48+
AC_CHECK_DECLS([SYS_waitid],,,
49+
[#include <sys/syscall.h>])
50+
4651
dnl if unsupported, -1 means automatically ENOSYS in this context
4752
AC_CACHE_CHECK([if sched_getcpu is supported], [php_cv_func_sched_getcpu],
4853
[AC_RUN_IFELSE([AC_LANG_SOURCE([

ext/pcntl/pcntl.c

+42-4
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,15 @@ typedef psetid_t cpu_set_t;
125125
#include <pthread/qos.h>
126126
#endif
127127

128-
#ifdef HAVE_PIDFD_OPEN
128+
#if defined(__linux__) && defined(HAVE_DECL_SYS_WAITID) && HAVE_DECL_SYS_WAITID == 1 && defined(HAVE_SYSCALL) && HAVE_SYSCALL == 1
129+
#define HAVE_LINUX_RAW_SYSCALL_WAITID 1
130+
#endif
131+
132+
#if defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
133+
#include <unistd.h>
134+
#endif
135+
136+
#if defined(HAVE_PIDFD_OPEN) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
129137
#include <sys/syscall.h>
130138
#endif
131139

@@ -406,19 +414,49 @@ PHP_FUNCTION(pcntl_waitid)
406414
bool id_is_null = 1;
407415
zval *user_siginfo = NULL;
408416
zend_long options = WEXITED;
417+
zval *z_rusage = NULL;
409418

410-
ZEND_PARSE_PARAMETERS_START(0, 4)
419+
siginfo_t siginfo;
420+
int status;
421+
422+
ZEND_PARSE_PARAMETERS_START(0, 5)
411423
Z_PARAM_OPTIONAL
412424
Z_PARAM_LONG(idtype)
413425
Z_PARAM_LONG_OR_NULL(id, id_is_null)
414426
Z_PARAM_ZVAL(user_siginfo)
415427
Z_PARAM_LONG(options)
428+
Z_PARAM_ZVAL(z_rusage)
416429
ZEND_PARSE_PARAMETERS_END();
417430

418431
errno = 0;
419-
siginfo_t siginfo;
432+
memset(&siginfo, 0, sizeof(siginfo_t));
420433

421-
int status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
434+
#if defined(HAVE_WAIT6) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID)
435+
if (z_rusage) {
436+
z_rusage = zend_try_array_init(z_rusage);
437+
if (!z_rusage) {
438+
RETURN_THROWS();
439+
}
440+
struct rusage rusage;
441+
# if defined(HAVE_WAIT6) /* FreeBSD */
442+
struct __wrusage wrusage;
443+
memset(&wrusage, 0, sizeof(struct __wrusage));
444+
int pid = wait6((idtype_t) idtype, (id_t) id, &status, (int) options, &wrusage, &siginfo);
445+
status = pid > 0 ? 0 : pid;
446+
memcpy(&rusage, &wrusage.wru_self, sizeof(struct rusage));
447+
# else /* Linux */
448+
memset(&rusage, 0, sizeof(struct rusage));
449+
status = syscall(SYS_waitid, (idtype_t) idtype, (id_t) id, &siginfo, (int) options, &rusage);
450+
# endif
451+
if (status == 0) {
452+
PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
453+
}
454+
} else { /* POSIX */
455+
status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
456+
}
457+
#else /* POSIX */
458+
status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options);
459+
#endif
422460

423461
if (status == -1) {
424462
PCNTL_G(last_error) = errno;

ext/pcntl/pcntl.stub.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -1006,8 +1006,11 @@ function pcntl_fork(): int {}
10061006
function pcntl_waitpid(int $process_id, &$status, int $flags = 0, &$resource_usage = []): int {}
10071007

10081008
#if defined (HAVE_WAITID) && defined (HAVE_POSIX_IDTYPES) && defined (HAVE_DECL_WEXITED) && HAVE_DECL_WEXITED == 1
1009-
/** @param array $info */
1010-
function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED): bool {}
1009+
/**
1010+
* @param array $info
1011+
* @param array $resource_usage
1012+
*/
1013+
function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED, &$resource_usage = []): bool {}
10111014
#endif
10121015

10131016
/**

ext/pcntl/pcntl_arginfo.h

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--TEST--
2+
pcntl_waitid() and rusage
3+
--EXTENSIONS--
4+
pcntl
5+
posix
6+
--SKIPIF--
7+
<?php
8+
if (!function_exists('pcntl_waitid')) die('skip pcntl_waitid unavailable');
9+
if (!str_contains(PHP_OS, 'Linux') && !str_contains(PHP_OS, 'FreeBSD')) {
10+
die('skip pcntl_waitid can return rusage only on FreeBSD and Linux');
11+
}
12+
?>
13+
--FILE--
14+
<?php
15+
$pid = pcntl_fork();
16+
if ($pid == -1) {
17+
die('failed');
18+
} else if ($pid) {
19+
$status = 0;
20+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WSTOPPED, $rusage));
21+
var_dump($rusage['ru_utime.tv_sec']);
22+
var_dump($rusage['ru_utime.tv_usec']);
23+
24+
posix_kill($pid, SIGCONT);
25+
$rusage = array(1,2,3);
26+
pcntl_waitid(P_PID, $pid, $status, WCONTINUED, $rusage);
27+
var_dump($rusage['ru_utime.tv_sec']);
28+
var_dump($rusage['ru_utime.tv_usec']);
29+
30+
posix_kill($pid, SIGUSR1);
31+
pcntl_waitid(P_PID, $pid, $status, WEXITED, $rusage);
32+
var_dump($rusage['ru_maxrss']);
33+
34+
$rusage = 'string';
35+
pcntl_waitid(P_PID, $pid, $status, WNOHANG, $rusage);
36+
var_dump(gettype($rusage));
37+
var_dump(count($rusage));
38+
39+
$rusage = new stdClass;
40+
pcntl_waitid(P_PID, $pid, $status, WNOHANG, $rusage);
41+
var_dump(gettype($rusage));
42+
var_dump(count($rusage));
43+
44+
fwrite(STDOUT, 'END' . PHP_EOL);
45+
} else {
46+
pcntl_signal(SIGUSR1, function ($_signo, $_siginfo) { exit(42); });
47+
posix_kill(posix_getpid(), SIGSTOP);
48+
pcntl_signal_dispatch();
49+
sleep(42);
50+
pcntl_signal_dispatch();
51+
exit(6);
52+
}
53+
?>
54+
--EXPECTF--
55+
bool(true)
56+
int(%d)
57+
int(%d)
58+
int(%d)
59+
int(%d)
60+
int(%d)
61+
string(5) "array"
62+
int(0)
63+
string(5) "array"
64+
int(0)
65+
END

0 commit comments

Comments
 (0)