Skip to content

Commit 4e86343

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) Changed int to pid_t
1 parent 56abb31 commit 4e86343

File tree

6 files changed

+132
-11
lines changed

6 files changed

+132
-11
lines changed

ext/pcntl/config.m4

Lines changed: 5 additions & 0 deletions
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

Lines changed: 42 additions & 4 deletions
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)
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

@@ -401,19 +409,49 @@ PHP_FUNCTION(pcntl_waitid)
401409
bool id_is_null = 1;
402410
zval *user_siginfo = NULL;
403411
zend_long options = WEXITED;
412+
zval *z_rusage = NULL;
404413

405-
ZEND_PARSE_PARAMETERS_START(0, 4)
414+
siginfo_t siginfo;
415+
int status;
416+
417+
ZEND_PARSE_PARAMETERS_START(0, 5)
406418
Z_PARAM_OPTIONAL
407419
Z_PARAM_LONG(idtype)
408420
Z_PARAM_LONG_OR_NULL(id, id_is_null)
409421
Z_PARAM_ZVAL(user_siginfo)
410422
Z_PARAM_LONG(options)
423+
Z_PARAM_ZVAL(z_rusage)
411424
ZEND_PARSE_PARAMETERS_END();
412425

413426
errno = 0;
414-
siginfo_t siginfo;
427+
memset(&siginfo, 0, sizeof(siginfo_t));
415428

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

418456
if (status == -1) {
419457
PCNTL_G(last_error) = errno;

ext/pcntl/pcntl.stub.php

Lines changed: 5 additions & 2 deletions
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

Lines changed: 2 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_waitid.phpt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ if ($pid == -1) {
2626
} else {
2727
pcntl_signal(SIGUSR1, function ($_signo, $_siginfo) { exit(42); });
2828
posix_kill(posix_getpid(), SIGSTOP);
29-
pcntl_signal_dispatch();
30-
sleep(42);
31-
pcntl_signal_dispatch();
32-
exit(6);
29+
$nanoseconds = 100;
30+
while (true) {
31+
pcntl_signal_dispatch();
32+
time_nanosleep(0, $nanoseconds);
33+
$nanoseconds *= 2;
34+
}
3335
}
3436
?>
3537
--EXPECTF--
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WSTOPPED, $rusage));
20+
var_dump($rusage['ru_utime.tv_sec']);
21+
var_dump($rusage['ru_utime.tv_usec']);
22+
23+
$rusage = array(1,2,3);
24+
posix_kill($pid, SIGCONT);
25+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WCONTINUED, $rusage));
26+
var_dump($rusage['ru_utime.tv_sec']);
27+
var_dump($rusage['ru_utime.tv_usec']);
28+
29+
posix_kill($pid, SIGUSR1);
30+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED, $rusage));
31+
var_dump($rusage['ru_maxrss']);
32+
var_dump($siginfo['status']);
33+
34+
$rusage = 'string';
35+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED | WNOHANG, $rusage));
36+
var_dump(gettype($rusage));
37+
var_dump(count($rusage));
38+
39+
$rusage = new stdClass;
40+
var_dump(pcntl_waitid(P_PID, $pid, $siginfo, WEXITED | 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+
$nanoseconds = 100;
49+
while (true) {
50+
pcntl_signal_dispatch();
51+
time_nanosleep(0, $nanoseconds);
52+
$nanoseconds *= 2;
53+
}
54+
}
55+
?>
56+
--EXPECTF--
57+
bool(true)
58+
int(%d)
59+
int(%d)
60+
bool(true)
61+
int(%d)
62+
int(%d)
63+
bool(true)
64+
int(%d)
65+
int(42)
66+
bool(false)
67+
string(5) "array"
68+
int(0)
69+
bool(false)
70+
string(5) "array"
71+
int(0)
72+
END

0 commit comments

Comments
 (0)