pcntl: Adding pcntl_rfork support.

This commit is contained in:
David Carlier 2021-05-23 11:02:33 +01:00 committed by Joe Watkins
parent 20ef668978
commit 28382aa1ec
No known key found for this signature in database
GPG key ID: F9BA0ADA31CBD89E
7 changed files with 144 additions and 1 deletions

View file

@ -346,6 +346,9 @@ PHP 8.1 UPGRADE NOTES
. Added array_is_list(array $array), which will return true if the array keys are 0 .. count($array)-1 in that order.
RFC: https://wiki.php.net/rfc/is_list
- pcntl:
. Added pcntl_rfork for FreeBSD variants
- Reflection:
. Added ReflectionFunctionAbstract::getClosureUsedVariables

View file

@ -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])
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork])
AC_MSG_CHECKING([for siginfo_t])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[

View file

@ -340,6 +340,36 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
REGISTER_LONG_CONSTANT("CLONE_NEWCGROUP", CLONE_NEWCGROUP, CONST_CS | CONST_PERSISTENT);
#endif
#endif
#ifdef HAVE_RFORK
#ifdef RFPROC
REGISTER_LONG_CONSTANT("RFPROC", RFPROC, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFNOWAIT
REGISTER_LONG_CONSTANT("RFNOWAIT", RFNOWAIT, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFCFDG
REGISTER_LONG_CONSTANT("RFCFDG", RFCFDG, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFFDG
REGISTER_LONG_CONSTANT("RFFDG", RFFDG, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFLINUXTHPN
REGISTER_LONG_CONSTANT("RFLINUXTHPN", RFLINUXTHPN, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFMEM
REGISTER_LONG_CONSTANT("RFMEM", RFMEM, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFSIGSHARE
REGISTER_LONG_CONSTANT("RFSIGSHARE", RFSIGSHARE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFSIGZMB
REGISTER_LONG_CONSTANT("RFSIGSZMB", RFSIGSZMB, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef RFTHREAD
REGISTER_LONG_CONSTANT("RFTHREAD", RFTHREAD, CONST_CS | CONST_PERSISTENT);
#endif
#endif
}
static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
@ -1468,6 +1498,54 @@ PHP_FUNCTION(pcntl_unshare)
/* }}} */
#endif
#ifdef HAVE_RFORK
/* {{{ proto bool pcntl_rfork([int flags|custom signal)
More control over the process creation is given over fork/vfork. */
PHP_FUNCTION(pcntl_rfork)
{
zend_long flags;
zend_long csignal;
pid_t pid;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_LONG(flags)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(csignal)
ZEND_PARSE_PARAMETERS_END();
/* This is a flag to use with great caution in general, preferably not within PHP */
if ((flags & RFMEM) != 0) {
flags &= ~RFMEM;
}
/* A new pid is required */
flags |= RFPROC;
if (ZEND_NUM_ARGS() == 2 && (flags & RFTSIGZMB) != 0) {
flags |= RFTSIGFLAGS(csignal);
}
pid = rfork(flags);
if (pid == -1) {
PCNTL_G(last_error) = errno;
switch (errno) {
case EINVAL:
php_error_docref(NULL, E_WARNING, "RFFDG and RFCFDG modes are mutually exclusive");
break;
case EAGAIN:
php_error_docref(NULL, E_WARNING, "Maximum process creations limit reached\n");
break;
default:
php_error_docref(NULL, E_WARNING, "Error %d", errno);
}
}
RETURN_LONG((zend_long) pid);
}
#endif
/* }}} */
static void pcntl_interrupt_function(zend_execute_data *execute_data)
{
pcntl_signal_dispatch();

View file

@ -79,3 +79,7 @@ function pcntl_async_signals(?bool $enable = null): bool {}
#ifdef HAVE_UNSHARE
function pcntl_unshare(int $flags): bool {}
#endif
#ifdef HAVE_RFORK
function pcntl_rfork(int $flags, int $signal): int{}
#endif

View file

@ -119,6 +119,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_unshare, 0, 1, _IS_BOOL, 0
ZEND_END_ARG_INFO()
#endif
#if defined(HAVE_RFORK)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_rfork, 0, 1, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, signal, IS_LONG, 0)
ZEND_END_ARG_INFO()
#endif
ZEND_FUNCTION(pcntl_fork);
ZEND_FUNCTION(pcntl_waitpid);
@ -158,6 +165,9 @@ ZEND_FUNCTION(pcntl_async_signals);
#if defined(HAVE_UNSHARE)
ZEND_FUNCTION(pcntl_unshare);
#endif
#if defined(HAVE_RFORK)
ZEND_FUNCTION(pcntl_rfork);
#endif
static const zend_function_entry ext_functions[] = {

View file

@ -0,0 +1,24 @@
--TEST--
Test function pcntl_rfork() with no flag.
--SKIPIF--
<?php
if (!extension_loaded('pcntl')) die('skip pcntl extension not available');
elseif (!extension_loaded('posix')) die('skip posix extension not available');
if (!function_exists('pcntl_rfork')) die('skip pcntl_rfork unavailable');
?>
--FILE--
<?php
echo "*** Test with no flags ***\n";
$pid = pcntl_rfork(0);
if ($pid > 0) {
pcntl_wait($status);
var_dump($pid);
} else {
var_dump($pid);
}
?>
--EXPECTF--
*** Test with no flags ***
int(0)
int(%d)

View file

@ -0,0 +1,24 @@
--TEST--
Test function pcntl_rfork() with no wait flag.
--SKIPIF--
<?php
if (!extension_loaded('pcntl')) die('skip pcntl extension not available');
elseif (!extension_loaded('posix')) die('skip posix extension not available');
if (!function_exists('pcntl_rfork')) die('skip pcntl_rfork unavailable');
?>
--FILE--
<?php
echo "*** Test by with child not reporting to the parent ***\n";
$pid = pcntl_rfork(RFNOWAIT|RFTSIGZMB,SIGUSR1);
if ($pid > 0) {
var_dump($pid);
} else {
var_dump($pid);
sleep(1);
}
?>
--EXPECTF--
*** Test by with child not reporting to the parent ***
int(%d)
int(0)