2001-06-12 16:54:25 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-01-30 17:03:12 +08:00
| Copyright ( c ) The PHP Group |
2001-06-12 16:54:25 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 20:51:34 +08:00
| This source file is subject to version 3.01 of the PHP license , |
2001-06-12 16:54:25 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2021-05-06 18:16:35 +08:00
| https : //www.php.net/license/3_01.txt |
2001-06-12 16:54:25 +08:00
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2002-02-28 16:29:35 +08:00
| Author : Jason Greene < jason @ inetgurus . net > |
2001-06-12 16:54:25 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2001-06-20 05:42:57 +08:00
# define PCNTL_DEBUG 0
# if PCNTL_DEBUG
# define DEBUG_OUT printf("DEBUG: ");printf
2002-08-22 12:20:10 +08:00
# define IF_DEBUG(z) z
2001-06-20 05:42:57 +08:00
# else
2002-08-22 12:20:10 +08:00
# define IF_DEBUG(z)
2001-06-20 05:42:57 +08:00
# endif
2001-06-12 16:54:25 +08:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include "php.h"
# include "php_ini.h"
2002-03-17 16:10:04 +08:00
# include "ext/standard/info.h"
2001-06-12 16:54:25 +08:00
# include "php_pcntl.h"
2008-08-05 23:12:19 +08:00
# include "php_signal.h"
# include "php_ticks.h"
2022-07-17 02:05:16 +08:00
# include "zend_fibers.h"
2001-06-12 16:54:25 +08:00
2020-05-20 19:59:44 +08:00
# if defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY) || defined(HAVE_WAIT3)
2008-08-05 23:12:19 +08:00
# include <sys/wait.h>
2003-02-18 09:41:06 +08:00
# include <sys/time.h>
# include <sys/resource.h>
# endif
2010-11-02 04:10:17 +08:00
# include <errno.h>
2024-04-06 04:37:59 +08:00
# if defined(HAVE_UNSHARE) || defined(HAVE_SCHED_SETAFFINITY)
2019-01-22 07:56:43 +08:00
# include <sched.h>
2024-04-06 04:37:59 +08:00
# if defined(__FreeBSD__)
# include <sys/types.h>
# include <sys/cpuset.h>
typedef cpuset_t cpu_set_t ;
# endif
2019-01-22 07:56:43 +08:00
# endif
2010-11-02 04:10:17 +08:00
2024-04-04 01:59:40 +08:00
# ifdef HAVE_PIDFD_OPEN
# include <sys/syscall.h>
# endif
2021-11-30 22:47:14 +08:00
# ifdef HAVE_FORKX
# include <sys/fork.h>
# endif
2015-08-05 22:42:42 +08:00
# ifndef NSIG
2021-05-18 22:31:30 +08:00
# define NSIG 32
2015-08-05 22:42:42 +08:00
# endif
2022-08-01 16:26:05 +08:00
# define LONG_CONST(c) (zend_long) c
# include "pcntl_arginfo.h"
2023-03-03 18:35:06 +08:00
# include "Zend/zend_max_execution_timer.h"
2001-06-12 16:54:25 +08:00
ZEND_DECLARE_MODULE_GLOBALS ( pcntl )
2006-06-16 02:33:09 +08:00
static PHP_GINIT_FUNCTION ( pcntl ) ;
2001-06-12 16:54:25 +08:00
zend_module_entry pcntl_module_entry = {
2001-10-12 07:33:59 +08:00
STANDARD_MODULE_HEADER ,
" pcntl " ,
2020-04-20 02:05:16 +08:00
ext_functions ,
2001-06-12 16:54:25 +08:00
PHP_MINIT ( pcntl ) ,
PHP_MSHUTDOWN ( pcntl ) ,
2002-08-22 12:20:10 +08:00
PHP_RINIT ( pcntl ) ,
PHP_RSHUTDOWN ( pcntl ) ,
2001-06-12 16:54:25 +08:00
PHP_MINFO ( pcntl ) ,
2015-03-24 03:54:55 +08:00
PHP_PCNTL_VERSION ,
2006-06-16 02:33:09 +08:00
PHP_MODULE_GLOBALS ( pcntl ) ,
PHP_GINIT ( pcntl ) ,
NULL ,
NULL ,
STANDARD_MODULE_PROPERTIES_EX
2001-06-12 16:54:25 +08:00
} ;
# ifdef COMPILE_DL_PCNTL
2019-03-12 19:15:47 +08:00
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE ( )
# endif
2001-06-12 16:54:25 +08:00
ZEND_GET_MODULE ( pcntl )
# endif
2003-05-30 07:39:41 +08:00
2016-07-06 18:11:47 +08:00
static void ( * orig_interrupt_function ) ( zend_execute_data * execute_data ) ;
2016-06-14 06:33:19 +08:00
# ifdef HAVE_STRUCT_SIGINFO_T
static void pcntl_signal_handler ( int , siginfo_t * , void * ) ;
static void pcntl_siginfo_to_zval ( int , siginfo_t * , zval * ) ;
# else
2003-05-30 07:39:41 +08:00
static void pcntl_signal_handler ( int ) ;
2016-06-14 06:33:19 +08:00
# endif
2021-05-13 01:54:57 +08:00
static void pcntl_signal_dispatch ( void ) ;
static void pcntl_signal_dispatch_tick_function ( int dummy_int , void * dummy_pointer ) ;
2016-07-06 18:11:47 +08:00
static void pcntl_interrupt_function ( zend_execute_data * execute_data ) ;
2015-01-03 17:22:58 +08:00
2006-06-16 02:33:09 +08:00
static PHP_GINIT_FUNCTION ( pcntl )
2015-01-03 17:22:58 +08:00
{
2019-03-12 19:15:47 +08:00
# if defined(COMPILE_DL_PCNTL) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE ( ) ;
# endif
2005-05-07 22:58:12 +08:00
memset ( pcntl_globals , 0 , sizeof ( * pcntl_globals ) ) ;
2001-07-31 03:40:29 +08:00
}
2002-08-22 12:20:10 +08:00
PHP_RINIT_FUNCTION ( pcntl )
2001-07-31 03:40:29 +08:00
{
2021-05-13 01:54:57 +08:00
php_add_tick_function ( pcntl_signal_dispatch_tick_function , NULL ) ;
2005-05-07 22:58:12 +08:00
zend_hash_init ( & PCNTL_G ( php_signal_table ) , 16 , NULL , ZVAL_PTR_DTOR , 0 ) ;
PCNTL_G ( head ) = PCNTL_G ( tail ) = PCNTL_G ( spares ) = NULL ;
2016-07-06 18:11:47 +08:00
PCNTL_G ( async_signals ) = 0 ;
2020-10-22 20:18:45 +08:00
PCNTL_G ( last_error ) = 0 ;
2021-05-18 22:31:30 +08:00
PCNTL_G ( num_signals ) = NSIG ;
# ifdef SIGRTMAX
/* At least FreeBSD reports an incorrecrt NSIG that does not include realtime signals.
* As SIGRTMAX may be a dynamic value , adjust the value in INIT . */
if ( NSIG < SIGRTMAX + 1 ) {
PCNTL_G ( num_signals ) = SIGRTMAX + 1 ;
}
# endif
2002-08-22 12:20:10 +08:00
return SUCCESS ;
2001-07-31 03:40:29 +08:00
}
PHP_MINIT_FUNCTION ( pcntl )
{
2022-08-01 16:26:05 +08:00
register_pcntl_symbols ( module_number ) ;
2016-07-06 18:11:47 +08:00
orig_interrupt_function = zend_interrupt_function ;
zend_interrupt_function = pcntl_interrupt_function ;
2002-08-22 12:20:10 +08:00
2001-06-12 16:54:25 +08:00
return SUCCESS ;
}
2001-07-31 03:40:29 +08:00
2001-06-12 16:54:25 +08:00
PHP_MSHUTDOWN_FUNCTION ( pcntl )
{
return SUCCESS ;
}
2002-08-22 12:20:10 +08:00
PHP_RSHUTDOWN_FUNCTION ( pcntl )
{
2005-05-07 22:58:12 +08:00
struct php_pcntl_pending_signal * sig ;
2022-11-08 20:25:56 +08:00
zend_long signo ;
zval * handle ;
/* Reset all signals to their default disposition */
ZEND_HASH_FOREACH_NUM_KEY_VAL ( & PCNTL_G ( php_signal_table ) , signo , handle ) {
if ( Z_TYPE_P ( handle ) ! = IS_LONG | | Z_LVAL_P ( handle ) ! = ( zend_long ) SIG_DFL ) {
php_signal ( signo , ( Sigfunc * ) ( zend_long ) SIG_DFL , 0 ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2005-05-07 22:58:12 +08:00
2002-08-22 12:20:10 +08:00
zend_hash_destroy ( & PCNTL_G ( php_signal_table ) ) ;
2022-11-08 20:25:56 +08:00
2005-05-07 22:58:12 +08:00
while ( PCNTL_G ( head ) ) {
sig = PCNTL_G ( head ) ;
PCNTL_G ( head ) = sig - > next ;
efree ( sig ) ;
}
while ( PCNTL_G ( spares ) ) {
sig = PCNTL_G ( spares ) ;
PCNTL_G ( spares ) = sig - > next ;
efree ( sig ) ;
}
2022-11-08 20:25:56 +08:00
2002-08-22 12:20:10 +08:00
return SUCCESS ;
}
2001-07-31 03:40:29 +08:00
2001-06-12 16:54:25 +08:00
PHP_MINFO_FUNCTION ( pcntl )
{
php_info_print_table_start ( ) ;
2022-09-06 14:48:22 +08:00
php_info_print_table_row ( 2 , " pcntl support " , " enabled " ) ;
2001-06-12 16:54:25 +08:00
php_info_print_table_end ( ) ;
}
2001-07-06 13:48:52 +08:00
2020-07-01 21:32:55 +08:00
/* {{{ Forks the currently running process following the same behavior as the UNIX fork() system call*/
2001-06-12 16:54:25 +08:00
PHP_FUNCTION ( pcntl_fork )
{
pid_t id ;
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_NONE ( ) ;
2019-08-27 23:25:19 +08:00
2002-03-17 06:31:57 +08:00
id = fork ( ) ;
2001-06-12 16:54:25 +08:00
if ( id = = - 1 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
2023-03-03 18:35:06 +08:00
} else if ( id = = 0 ) {
zend_max_execution_timer_init ( ) ;
2001-06-12 16:54:25 +08:00
}
2015-01-03 17:22:58 +08:00
2014-08-26 17:23:25 +08:00
RETURN_LONG ( ( zend_long ) id ) ;
2001-06-12 16:54:25 +08:00
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Set an alarm clock for delivery of a signal*/
2002-06-04 23:51:25 +08:00
PHP_FUNCTION ( pcntl_alarm )
{
2014-08-26 01:24:55 +08:00
zend_long seconds ;
2002-06-04 23:51:25 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( seconds ) ;
ZEND_PARSE_PARAMETERS_END ( ) ;
2015-01-03 17:22:58 +08:00
2019-08-27 23:25:19 +08:00
RETURN_LONG ( ( zend_long ) alarm ( seconds ) ) ;
2002-06-04 23:51:25 +08:00
}
/* }}} */
2014-12-11 22:01:55 +08:00
# define PHP_RUSAGE_PARA(from, to, field) \
add_assoc_long ( to , # field , from . field )
2017-08-30 04:03:56 +08:00
# ifndef _OSD_POSIX
2014-12-11 22:01:55 +08:00
# define PHP_RUSAGE_SPECIAL(from, to) \
PHP_RUSAGE_PARA ( from , to , ru_oublock ) ; \
PHP_RUSAGE_PARA ( from , to , ru_inblock ) ; \
PHP_RUSAGE_PARA ( from , to , ru_msgsnd ) ; \
PHP_RUSAGE_PARA ( from , to , ru_msgrcv ) ; \
PHP_RUSAGE_PARA ( from , to , ru_maxrss ) ; \
PHP_RUSAGE_PARA ( from , to , ru_ixrss ) ; \
PHP_RUSAGE_PARA ( from , to , ru_idrss ) ; \
PHP_RUSAGE_PARA ( from , to , ru_minflt ) ; \
PHP_RUSAGE_PARA ( from , to , ru_majflt ) ; \
PHP_RUSAGE_PARA ( from , to , ru_nsignals ) ; \
PHP_RUSAGE_PARA ( from , to , ru_nvcsw ) ; \
PHP_RUSAGE_PARA ( from , to , ru_nivcsw ) ; \
PHP_RUSAGE_PARA ( from , to , ru_nswap ) ;
# else /*_OSD_POSIX*/
# define PHP_RUSAGE_SPECIAL(from, to)
# endif
# define PHP_RUSAGE_COMMON(from ,to) \
PHP_RUSAGE_PARA ( from , to , ru_utime . tv_usec ) ; \
PHP_RUSAGE_PARA ( from , to , ru_utime . tv_sec ) ; \
PHP_RUSAGE_PARA ( from , to , ru_stime . tv_usec ) ; \
PHP_RUSAGE_PARA ( from , to , ru_stime . tv_sec ) ;
# define PHP_RUSAGE_TO_ARRAY(from, to) \
if ( to ) { \
PHP_RUSAGE_SPECIAL ( from , to ) \
PHP_RUSAGE_COMMON ( from , to ) ; \
}
2020-07-01 21:32:55 +08:00
/* {{{ Waits on or returns the status of a forked child as defined by the waitpid() system call */
2001-06-12 16:54:25 +08:00
PHP_FUNCTION ( pcntl_waitpid )
{
2014-08-26 01:24:55 +08:00
zend_long pid , options = 0 ;
2014-12-11 22:01:55 +08:00
zval * z_status = NULL , * z_rusage = NULL ;
2002-04-24 05:21:41 +08:00
int status ;
pid_t child_id ;
2014-12-11 22:01:55 +08:00
# ifdef HAVE_WAIT4
struct rusage rusage ;
# endif
2001-06-12 16:54:25 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 2 , 4 )
Z_PARAM_LONG ( pid )
Z_PARAM_ZVAL ( z_status )
Z_PARAM_OPTIONAL
Z_PARAM_LONG ( options )
Z_PARAM_ZVAL ( z_rusage )
ZEND_PARSE_PARAMETERS_END ( ) ;
2015-01-03 17:22:58 +08:00
2016-05-05 15:18:17 +08:00
status = zval_get_long ( z_status ) ;
2001-06-12 16:54:25 +08:00
2014-12-11 22:01:55 +08:00
# ifdef HAVE_WAIT4
if ( z_rusage ) {
2019-01-07 19:28:51 +08:00
z_rusage = zend_try_array_init ( z_rusage ) ;
if ( ! z_rusage ) {
2020-01-04 03:44:29 +08:00
RETURN_THROWS ( ) ;
2014-12-11 22:01:55 +08:00
}
memset ( & rusage , 0 , sizeof ( struct rusage ) ) ;
child_id = wait4 ( ( pid_t ) pid , & status , options , & rusage ) ;
} else {
child_id = waitpid ( ( pid_t ) pid , & status , options ) ;
}
# else
2002-04-24 05:21:41 +08:00
child_id = waitpid ( ( pid_t ) pid , & status , options ) ;
2014-12-11 22:01:55 +08:00
# endif
2002-04-24 05:21:41 +08:00
2010-11-02 04:10:17 +08:00
if ( child_id < 0 ) {
PCNTL_G ( last_error ) = errno ;
}
2014-12-11 22:01:55 +08:00
# ifdef HAVE_WAIT4
if ( child_id > 0 ) {
PHP_RUSAGE_TO_ARRAY ( rusage , z_rusage ) ;
}
# endif
2019-04-24 23:28:29 +08:00
ZEND_TRY_ASSIGN_REF_LONG ( z_status , status ) ;
2002-04-24 05:21:41 +08:00
2014-08-26 01:24:55 +08:00
RETURN_LONG ( ( zend_long ) child_id ) ;
2001-06-12 16:54:25 +08:00
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Waits on or returns the status of a forked child as defined by the waitpid() system call */
2003-10-29 01:08:18 +08:00
PHP_FUNCTION ( pcntl_wait )
{
2014-08-26 01:24:55 +08:00
zend_long options = 0 ;
2014-12-11 22:01:55 +08:00
zval * z_status = NULL , * z_rusage = NULL ;
2003-10-29 01:08:18 +08:00
int status ;
pid_t child_id ;
2014-12-11 22:01:55 +08:00
# ifdef HAVE_WAIT3
struct rusage rusage ;
# endif
2003-10-29 01:08:18 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 3 )
Z_PARAM_ZVAL ( z_status )
Z_PARAM_OPTIONAL
Z_PARAM_LONG ( options )
Z_PARAM_ZVAL ( z_rusage )
ZEND_PARSE_PARAMETERS_END ( ) ;
2015-01-03 17:22:58 +08:00
2016-05-05 15:18:17 +08:00
status = zval_get_long ( z_status ) ;
2003-10-29 01:08:18 +08:00
# ifdef HAVE_WAIT3
2014-12-11 22:01:55 +08:00
if ( z_rusage ) {
2019-01-07 19:28:51 +08:00
z_rusage = zend_try_array_init ( z_rusage ) ;
if ( ! z_rusage ) {
2020-01-04 03:44:29 +08:00
RETURN_THROWS ( ) ;
2014-12-11 22:01:55 +08:00
}
memset ( & rusage , 0 , sizeof ( struct rusage ) ) ;
child_id = wait3 ( & status , options , & rusage ) ;
} else if ( options ) {
child_id = wait3 ( & status , options , NULL ) ;
} else {
2003-10-29 01:08:18 +08:00
child_id = wait ( & status ) ;
}
# else
child_id = wait ( & status ) ;
# endif
2010-11-02 04:10:17 +08:00
if ( child_id < 0 ) {
PCNTL_G ( last_error ) = errno ;
}
2014-12-11 22:01:55 +08:00
# ifdef HAVE_WAIT3
if ( child_id > 0 ) {
PHP_RUSAGE_TO_ARRAY ( rusage , z_rusage ) ;
}
# endif
2016-05-05 15:18:17 +08:00
2019-04-24 23:28:29 +08:00
ZEND_TRY_ASSIGN_REF_LONG ( z_status , status ) ;
2003-10-29 01:08:18 +08:00
2014-08-26 01:24:55 +08:00
RETURN_LONG ( ( zend_long ) child_id ) ;
2003-10-29 01:08:18 +08:00
}
/* }}} */
2014-12-11 22:01:55 +08:00
# undef PHP_RUSAGE_PARA
# undef PHP_RUSAGE_SPECIAL
# undef PHP_RUSAGE_COMMON
# undef PHP_RUSAGE_TO_ARRAY
2020-07-01 21:32:55 +08:00
/* {{{ Returns true if the child status code represents a successful exit */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wifexited )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2008-06-22 23:16:11 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WIFEXITED
int int_status_word = ( int ) status_word ;
if ( WIFEXITED ( int_status_word ) ) {
2008-06-22 23:16:11 +08:00
RETURN_TRUE ;
2019-08-27 23:25:19 +08:00
}
2001-07-06 13:48:52 +08:00
# endif
2018-02-23 23:11:18 +08:00
2001-07-06 13:48:52 +08:00
RETURN_FALSE ;
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wifstopped )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2008-06-22 23:16:11 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WIFSTOPPED
int int_status_word = ( int ) status_word ;
if ( WIFSTOPPED ( int_status_word ) ) {
2008-06-22 23:16:11 +08:00
RETURN_TRUE ;
2019-08-27 23:25:19 +08:00
}
2001-07-06 13:48:52 +08:00
# endif
2019-08-27 23:25:19 +08:00
2001-07-06 13:48:52 +08:00
RETURN_FALSE ;
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Returns true if the child status code represents a process that was terminated due to a signal */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wifsignaled )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2008-06-22 23:16:11 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WIFSIGNALED
int int_status_word = ( int ) status_word ;
if ( WIFSIGNALED ( int_status_word ) ) {
2008-06-22 23:16:11 +08:00
RETURN_TRUE ;
2019-08-27 23:25:19 +08:00
}
2001-07-06 13:48:52 +08:00
# endif
2019-08-27 23:25:19 +08:00
2001-07-06 13:48:52 +08:00
RETURN_FALSE ;
}
/* }}} */
2021-12-21 14:17:12 +08:00
2020-07-01 21:32:55 +08:00
/* {{{ Returns true if the child status code represents a process that was resumed due to a SIGCONT signal */
2015-02-23 21:38:55 +08:00
PHP_FUNCTION ( pcntl_wifcontinued )
{
zend_long status_word ;
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2015-02-23 21:38:55 +08:00
2019-08-27 23:25:19 +08:00
# ifdef HAVE_WCONTINUED
int int_status_word = ( int ) status_word ;
if ( WIFCONTINUED ( int_status_word ) ) {
2015-02-23 21:38:55 +08:00
RETURN_TRUE ;
2019-08-27 23:25:19 +08:00
}
2015-02-23 21:38:55 +08:00
# endif
RETURN_FALSE ;
}
/* }}} */
2001-07-06 13:48:52 +08:00
2020-07-01 21:32:55 +08:00
/* {{{ Returns the status code of a child's exit */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wexitstatus )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2001-07-06 13:48:52 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WEXITSTATUS
int int_status_word = ( int ) status_word ;
2018-02-28 09:13:28 +08:00
RETURN_LONG ( WEXITSTATUS ( int_status_word ) ) ;
2001-07-06 13:48:52 +08:00
# else
RETURN_FALSE ;
# endif
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Returns the number of the signal that terminated the process who's status code is passed */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wtermsig )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2008-06-22 23:16:11 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WTERMSIG
int int_status_word = ( int ) status_word ;
2018-02-28 09:13:28 +08:00
RETURN_LONG ( WTERMSIG ( int_status_word ) ) ;
2001-07-06 13:48:52 +08:00
# else
RETURN_FALSE ;
# endif
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Returns the number of the signal that caused the process to stop who's status code is passed */
2001-07-06 13:48:52 +08:00
PHP_FUNCTION ( pcntl_wstopsig )
{
2014-08-26 01:24:55 +08:00
zend_long status_word ;
2008-06-22 23:16:11 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( status_word )
ZEND_PARSE_PARAMETERS_END ( ) ;
2001-07-06 13:48:52 +08:00
2019-08-27 23:25:19 +08:00
# ifdef WSTOPSIG
int int_status_word = ( int ) status_word ;
2018-02-28 09:13:28 +08:00
RETURN_LONG ( WSTOPSIG ( int_status_word ) ) ;
2001-07-06 13:48:52 +08:00
# else
RETURN_FALSE ;
# endif
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Executes specified program in current process space as defined by exec(2) */
2001-09-30 14:59:12 +08:00
PHP_FUNCTION ( pcntl_exec )
{
2008-09-13 03:49:18 +08:00
zval * args = NULL , * envs = NULL ;
2014-05-06 18:23:56 +08:00
zval * element ;
2001-09-30 14:59:12 +08:00
HashTable * args_hash , * envs_hash ;
2002-03-17 06:31:57 +08:00
int argc = 0 , argi = 0 ;
int envc = 0 , envi = 0 ;
char * * argv = NULL , * * envp = NULL ;
char * * current_arg , * * pair ;
2021-04-09 19:09:21 +08:00
size_t pair_length ;
2014-05-06 18:23:56 +08:00
zend_string * key ;
2001-09-30 14:59:12 +08:00
char * path ;
2014-08-27 21:31:48 +08:00
size_t path_len ;
2014-08-26 01:24:55 +08:00
zend_ulong key_num ;
2015-01-03 17:22:58 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 3 )
Z_PARAM_PATH ( path , path_len )
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY ( args )
Z_PARAM_ARRAY ( envs )
ZEND_PARSE_PARAMETERS_END ( ) ;
2015-01-03 17:22:58 +08:00
2002-03-17 06:31:57 +08:00
if ( ZEND_NUM_ARGS ( ) > 1 ) {
2012-03-28 22:18:23 +08:00
/* Build argument list */
2019-02-26 22:32:18 +08:00
SEPARATE_ARRAY ( args ) ;
2015-09-25 03:39:59 +08:00
args_hash = Z_ARRVAL_P ( args ) ;
2002-03-17 06:31:57 +08:00
argc = zend_hash_num_elements ( args_hash ) ;
2015-01-03 17:22:58 +08:00
2004-06-30 09:12:06 +08:00
argv = safe_emalloc ( ( argc + 2 ) , sizeof ( char * ) , 0 ) ;
2002-03-17 06:31:57 +08:00
* argv = path ;
2014-05-28 21:30:05 +08:00
current_arg = argv + 1 ;
ZEND_HASH_FOREACH_VAL ( args_hash , element ) {
if ( argi > = argc ) break ;
2019-02-26 22:32:18 +08:00
if ( ! try_convert_to_string ( element ) ) {
efree ( argv ) ;
2020-01-04 00:04:06 +08:00
RETURN_THROWS ( ) ;
2019-02-26 22:32:18 +08:00
}
2014-05-06 18:23:56 +08:00
* current_arg = Z_STRVAL_P ( element ) ;
2014-05-28 21:30:05 +08:00
argi + + ;
current_arg + + ;
} ZEND_HASH_FOREACH_END ( ) ;
2019-02-26 22:32:18 +08:00
* current_arg = NULL ;
2001-09-30 14:59:12 +08:00
} else {
2004-06-30 09:12:06 +08:00
argv = emalloc ( 2 * sizeof ( char * ) ) ;
2019-02-26 22:32:18 +08:00
argv [ 0 ] = path ;
argv [ 1 ] = NULL ;
2001-09-30 14:59:12 +08:00
}
2002-03-17 06:31:57 +08:00
if ( ZEND_NUM_ARGS ( ) = = 3 ) {
2001-09-30 14:59:12 +08:00
/* Build environment pair list */
2019-02-26 22:32:18 +08:00
SEPARATE_ARRAY ( envs ) ;
2015-09-25 03:39:59 +08:00
envs_hash = Z_ARRVAL_P ( envs ) ;
2002-03-17 06:31:57 +08:00
envc = zend_hash_num_elements ( envs_hash ) ;
2015-01-03 17:22:58 +08:00
pair = envp = safe_emalloc ( ( envc + 1 ) , sizeof ( char * ) , 0 ) ;
2014-05-28 21:30:05 +08:00
ZEND_HASH_FOREACH_KEY_VAL ( envs_hash , key_num , key , element ) {
if ( envi > = envc ) break ;
if ( ! key ) {
2014-08-26 04:47:04 +08:00
key = zend_long_to_str ( key_num ) ;
2014-05-28 21:30:05 +08:00
} else {
2014-08-26 01:24:55 +08:00
zend_string_addref ( key ) ;
2001-09-30 14:59:12 +08:00
}
2002-05-07 03:48:39 +08:00
2019-02-26 22:32:18 +08:00
if ( ! try_convert_to_string ( element ) ) {
zend_string_release ( key ) ;
efree ( argv ) ;
efree ( envp ) ;
2020-01-04 00:04:06 +08:00
RETURN_THROWS ( ) ;
2019-02-26 22:32:18 +08:00
}
2002-05-07 03:48:39 +08:00
2015-01-03 17:22:58 +08:00
/* Length of element + equal sign + length of key + null */
2021-04-09 19:09:21 +08:00
ZEND_ASSERT ( Z_STRLEN_P ( element ) < SIZE_MAX & & ZSTR_LEN ( key ) < SIZE_MAX ) ;
* pair = safe_emalloc ( Z_STRLEN_P ( element ) + 1 , sizeof ( char ) , ZSTR_LEN ( key ) + 1 ) ;
2015-06-30 09:05:24 +08:00
pair_length = Z_STRLEN_P ( element ) + ZSTR_LEN ( key ) + 2 ;
strlcpy ( * pair , ZSTR_VAL ( key ) , ZSTR_LEN ( key ) + 1 ) ;
2001-09-30 14:59:12 +08:00
strlcat ( * pair , " = " , pair_length ) ;
2014-05-06 18:23:56 +08:00
strlcat ( * pair , Z_STRVAL_P ( element ) , pair_length ) ;
2015-01-03 17:22:58 +08:00
2001-09-30 14:59:12 +08:00
/* Cleanup */
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( key , 0 ) ;
2014-05-28 21:30:05 +08:00
envi + + ;
pair + + ;
} ZEND_HASH_FOREACH_END ( ) ;
2002-03-17 06:31:57 +08:00
* ( pair ) = NULL ;
2009-09-30 21:04:28 +08:00
if ( execve ( path , argv , envp ) = = - 1 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error has occurred: (errno %d) %s " , errno , strerror ( errno ) ) ;
2009-09-30 21:04:28 +08:00
}
2015-01-03 17:22:58 +08:00
2009-09-30 21:04:28 +08:00
/* Cleanup */
2002-05-07 03:48:39 +08:00
for ( pair = envp ; * pair ! = NULL ; pair + + ) efree ( * pair ) ;
2004-06-30 09:12:06 +08:00
efree ( envp ) ;
2009-09-30 21:04:28 +08:00
} else {
if ( execv ( path , argv ) = = - 1 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error has occurred: (errno %d) %s " , errno , strerror ( errno ) ) ;
2009-09-30 21:04:28 +08:00
}
2002-05-07 03:48:39 +08:00
}
2004-06-30 09:12:06 +08:00
efree ( argv ) ;
2015-01-03 17:22:58 +08:00
2001-09-30 14:59:12 +08:00
RETURN_FALSE ;
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Assigns a system signal handler to a PHP function */
2001-06-12 16:54:25 +08:00
PHP_FUNCTION ( pcntl_signal )
{
2014-05-06 18:23:56 +08:00
zval * handle ;
2014-08-26 01:24:55 +08:00
zend_long signo ;
2021-01-15 19:30:54 +08:00
bool restart_syscalls = 1 ;
bool restart_syscalls_is_null = 1 ;
2001-06-12 16:54:25 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 2 , 3 )
Z_PARAM_LONG ( signo )
Z_PARAM_ZVAL ( handle )
Z_PARAM_OPTIONAL
Z_PARAM_BOOL_OR_NULL ( restart_syscalls , restart_syscalls_is_null )
ZEND_PARSE_PARAMETERS_END ( ) ;
2001-06-12 16:54:25 +08:00
2020-08-18 04:37:20 +08:00
if ( signo < 1 ) {
zend_argument_value_error ( 1 , " must be greater than or equal to 1 " ) ;
RETURN_THROWS ( ) ;
}
2021-05-18 22:31:30 +08:00
if ( signo > = PCNTL_G ( num_signals ) ) {
zend_argument_value_error ( 1 , " must be less than %d " , PCNTL_G ( num_signals ) ) ;
2020-08-18 04:37:20 +08:00
RETURN_THROWS ( ) ;
2011-06-04 01:18:46 +08:00
}
2005-05-07 22:58:12 +08:00
if ( ! PCNTL_G ( spares ) ) {
/* since calling malloc() from within a signal handler is not portable,
* pre - allocate a few records for recording signals */
int i ;
2021-05-18 22:31:30 +08:00
for ( i = 0 ; i < PCNTL_G ( num_signals ) ; i + + ) {
2005-05-07 22:58:12 +08:00
struct php_pcntl_pending_signal * psig ;
psig = emalloc ( sizeof ( * psig ) ) ;
psig - > next = PCNTL_G ( spares ) ;
PCNTL_G ( spares ) = psig ;
}
}
2019-01-14 20:04:37 +08:00
/* If restart_syscalls was not explicitly specified and the signal is SIGALRM, then default
* restart_syscalls to false . PHP used to enforce that restart_syscalls is false for SIGALRM ,
* so we keep this differing default to reduce the degree of BC breakage . */
if ( restart_syscalls_is_null & & signo = = SIGALRM ) {
restart_syscalls = 0 ;
}
2001-06-12 16:54:25 +08:00
/* Special long value case for SIG_DFL and SIG_IGN */
2014-08-26 01:24:55 +08:00
if ( Z_TYPE_P ( handle ) = = IS_LONG ) {
if ( Z_LVAL_P ( handle ) ! = ( zend_long ) SIG_DFL & & Z_LVAL_P ( handle ) ! = ( zend_long ) SIG_IGN ) {
2020-08-18 04:37:20 +08:00
zend_argument_value_error ( 2 , " must be either SIG_DFL or SIG_IGN when an integer value is given " ) ;
RETURN_THROWS ( ) ;
2001-06-12 16:54:25 +08:00
}
2020-04-15 16:37:33 +08:00
if ( php_signal ( signo , ( Sigfunc * ) Z_LVAL_P ( handle ) , ( int ) restart_syscalls ) = = ( void * ) SIG_ERR ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error assigning signal " ) ;
2002-03-17 06:31:57 +08:00
RETURN_FALSE ;
2001-06-12 16:54:25 +08:00
}
2016-07-03 00:44:17 +08:00
zend_hash_index_update ( & PCNTL_G ( php_signal_table ) , signo , handle ) ;
2001-06-12 16:54:25 +08:00
RETURN_TRUE ;
2002-03-17 06:31:57 +08:00
}
2015-01-03 17:22:58 +08:00
2023-10-16 00:24:18 +08:00
if ( ! zend_is_callable_ex ( handle , NULL , 0 , NULL , NULL , NULL ) ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = EINVAL ;
2020-08-18 04:37:20 +08:00
2023-01-23 17:52:14 +08:00
zend_argument_type_error ( 2 , " must be of type callable|int, %s given " , zend_zval_value_name ( handle ) ) ;
2020-08-18 04:37:20 +08:00
RETURN_THROWS ( ) ;
2001-06-12 16:54:25 +08:00
}
2015-01-03 17:22:58 +08:00
2002-08-22 12:20:10 +08:00
/* Add the function name to our signal table */
2018-06-01 16:58:57 +08:00
handle = zend_hash_index_update ( & PCNTL_G ( php_signal_table ) , signo , handle ) ;
Z_TRY_ADDREF_P ( handle ) ;
2015-01-03 17:22:58 +08:00
2020-04-15 16:37:33 +08:00
if ( php_signal4 ( signo , pcntl_signal_handler , ( int ) restart_syscalls , 1 ) = = ( void * ) SIG_ERR ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error assigning signal " ) ;
2002-08-22 12:20:10 +08:00
RETURN_FALSE ;
2001-06-12 16:54:25 +08:00
}
2002-03-17 06:31:57 +08:00
RETURN_TRUE ;
2001-06-12 16:54:25 +08:00
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Gets signal handler */
2016-07-03 00:44:17 +08:00
PHP_FUNCTION ( pcntl_signal_get_handler )
{
zval * prev_handle ;
zend_long signo ;
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( signo )
ZEND_PARSE_PARAMETERS_END ( ) ;
2016-07-03 00:44:17 +08:00
if ( signo < 1 | | signo > 32 ) {
2020-08-18 04:37:20 +08:00
zend_argument_value_error ( 1 , " must be between 1 and 32 " ) ;
RETURN_THROWS ( ) ;
2016-07-03 00:44:17 +08:00
}
if ( ( prev_handle = zend_hash_index_find ( & PCNTL_G ( php_signal_table ) , signo ) ) ! = NULL ) {
2020-01-20 17:34:17 +08:00
RETURN_COPY ( prev_handle ) ;
2016-07-03 00:44:17 +08:00
} else {
2016-07-06 20:54:51 +08:00
RETURN_LONG ( ( zend_long ) SIG_DFL ) ;
2016-07-03 00:44:17 +08:00
}
}
2020-07-01 21:32:55 +08:00
/* {{{ Dispatch signals to signal handlers */
2008-07-30 00:46:11 +08:00
PHP_FUNCTION ( pcntl_signal_dispatch )
{
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_NONE ( ) ;
2019-08-27 23:25:19 +08:00
2008-07-30 00:46:11 +08:00
pcntl_signal_dispatch ( ) ;
RETURN_TRUE ;
}
/* }}} */
2023-11-16 08:40:18 +08:00
/* Common helper function for these 3 wrapper functions */
# if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) || defined(HAVE_SIGPROCMASK)
static bool php_pcntl_set_user_signal_infos (
/* const */ HashTable * const user_signals ,
sigset_t * const set ,
size_t arg_num ,
bool allow_empty_signal_array
) {
if ( ! allow_empty_signal_array & & zend_hash_num_elements ( user_signals ) = = 0 ) {
zend_argument_value_error ( arg_num , " cannot be empty " ) ;
return false ;
}
errno = 0 ;
if ( sigemptyset ( set ) ! = 0 ) {
PCNTL_G ( last_error ) = errno ;
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
return false ;
}
zval * user_signal_no ;
ZEND_HASH_FOREACH_VAL ( user_signals , user_signal_no ) {
bool failed = true ;
zend_long tmp = zval_try_get_long ( user_signal_no , & failed ) ;
if ( failed ) {
zend_argument_type_error ( arg_num , " signals must be of type int, %s given " , zend_zval_value_name ( user_signal_no ) ) ;
return false ;
}
/* Signals are positive integers */
if ( tmp < 1 | | tmp > = PCNTL_G ( num_signals ) ) {
/* PCNTL_G(num_signals) stores +1 from the last valid signal */
zend_argument_value_error ( arg_num , " signals must be between 1 and %d " , PCNTL_G ( num_signals ) - 1 ) ;
return false ;
}
int signal_no = ( int ) tmp ;
errno = 0 ;
if ( sigaddset ( set , signal_no ) ! = 0 ) {
PCNTL_G ( last_error ) = errno ;
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
return false ;
}
} ZEND_HASH_FOREACH_END ( ) ;
return true ;
}
# endif
2008-07-30 00:59:10 +08:00
# ifdef HAVE_SIGPROCMASK
2020-07-01 21:32:55 +08:00
/* {{{ Examine and change blocked signals */
2008-07-30 00:59:10 +08:00
PHP_FUNCTION ( pcntl_sigprocmask )
{
2023-11-16 08:40:18 +08:00
zend_long how ;
HashTable * user_set ;
/* Optional by-ref out-param array of old signals */
zval * user_old_set = NULL ;
2008-07-30 00:59:10 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 2 , 3 )
Z_PARAM_LONG ( how )
2023-11-16 08:40:18 +08:00
Z_PARAM_ARRAY_HT ( user_set )
2021-12-21 14:17:12 +08:00
Z_PARAM_OPTIONAL
2023-11-16 08:40:18 +08:00
Z_PARAM_ZVAL ( user_old_set )
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_END ( ) ;
2008-07-30 00:59:10 +08:00
2023-11-16 08:40:18 +08:00
if ( how ! = SIG_BLOCK & & how ! = SIG_UNBLOCK & & how ! = SIG_SETMASK ) {
zend_argument_value_error ( 1 , " must be one of SIG_BLOCK, SIG_UNBLOCK, or SIG_SETMASK " ) ;
RETURN_THROWS ( ) ;
}
errno = 0 ;
sigset_t old_set ;
if ( sigemptyset ( & old_set ) ! = 0 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
2008-07-30 00:59:10 +08:00
RETURN_FALSE ;
}
2023-11-16 08:40:18 +08:00
sigset_t set ;
bool status = php_pcntl_set_user_signal_infos ( user_set , & set , 2 , /* allow_empty_signal_array */ how = = SIG_SETMASK ) ;
/* Some error occurred */
if ( ! status ) {
RETURN_FALSE ;
}
2008-07-30 00:59:10 +08:00
2023-11-16 08:40:18 +08:00
if ( sigprocmask ( how , & set , & old_set ) ! = 0 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
2008-07-30 00:59:10 +08:00
RETURN_FALSE ;
}
2023-11-16 08:40:18 +08:00
if ( user_old_set ! = NULL ) {
user_old_set = zend_try_array_init ( user_old_set ) ;
if ( ! user_old_set ) {
2020-01-04 03:44:29 +08:00
RETURN_THROWS ( ) ;
2008-11-10 13:57:18 +08:00
}
2019-01-07 19:28:51 +08:00
2023-11-16 08:40:18 +08:00
for ( int signal_no = 1 ; signal_no < PCNTL_G ( num_signals ) ; + + signal_no ) {
if ( sigismember ( & old_set , signal_no ) ! = 1 ) {
2008-11-10 13:57:18 +08:00
continue ;
}
2023-11-16 08:40:18 +08:00
add_next_index_long ( user_old_set , signal_no ) ;
2008-11-10 13:57:18 +08:00
}
}
2008-07-30 00:59:10 +08:00
RETURN_TRUE ;
}
/* }}} */
# endif
2016-06-14 06:33:19 +08:00
# ifdef HAVE_STRUCT_SIGINFO_T
2023-11-16 08:40:18 +08:00
# ifdef HAVE_SIGWAITINFO
/* {{{ Synchronously wait for queued signals */
PHP_FUNCTION ( pcntl_sigwaitinfo )
2008-07-30 00:59:10 +08:00
{
2023-11-16 08:40:18 +08:00
HashTable * user_set ;
/* Optional by-ref array of ints */
zval * user_siginfo = NULL ;
2008-07-30 00:59:10 +08:00
2023-11-16 08:40:18 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 2 )
Z_PARAM_ARRAY_HT ( user_set )
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL ( user_siginfo )
ZEND_PARSE_PARAMETERS_END ( ) ;
sigset_t set ;
bool status = php_pcntl_set_user_signal_infos ( user_set , & set , 1 , /* allow_empty_signal_array */ false ) ;
/* Some error occurred */
if ( ! status ) {
2008-07-30 00:59:10 +08:00
RETURN_FALSE ;
}
2023-11-16 08:40:18 +08:00
errno = 0 ;
siginfo_t siginfo ;
int signal_no = sigwaitinfo ( & set , & siginfo ) ;
/* sigwaitinfo() never sets errno to EAGAIN according to POSIX */
if ( signal_no = = - 1 ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
2023-11-16 08:40:18 +08:00
RETURN_FALSE ;
2008-07-30 00:59:10 +08:00
}
2023-11-16 08:40:18 +08:00
/* sigwaitinfo can return 0 on success on some platforms, e.g. NetBSD */
if ( ! signal_no & & siginfo . si_signo ) {
signal_no = siginfo . si_signo ;
2009-03-28 11:21:04 +08:00
}
2016-06-14 06:33:19 +08:00
2023-11-16 08:40:18 +08:00
pcntl_siginfo_to_zval ( signal_no , & siginfo , user_siginfo ) ;
RETURN_LONG ( signal_no ) ;
2016-06-14 06:33:19 +08:00
}
/* }}} */
2023-11-16 08:40:18 +08:00
# endif
# ifdef HAVE_SIGTIMEDWAIT
2020-07-01 21:32:55 +08:00
/* {{{ Wait for queued signals */
2016-06-14 06:33:19 +08:00
PHP_FUNCTION ( pcntl_sigtimedwait )
{
2023-11-16 08:40:18 +08:00
HashTable * user_set ;
/* Optional by-ref array of ints */
zval * user_siginfo = NULL ;
zend_long tv_sec = 0 ;
zend_long tv_nsec = 0 ;
ZEND_PARSE_PARAMETERS_START ( 1 , 4 )
Z_PARAM_ARRAY_HT ( user_set )
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL ( user_siginfo )
Z_PARAM_LONG ( tv_sec )
Z_PARAM_LONG ( tv_nsec )
ZEND_PARSE_PARAMETERS_END ( ) ;
sigset_t set ;
bool status = php_pcntl_set_user_signal_infos ( user_set , & set , 1 , /* allow_empty_signal_array */ false ) ;
/* Some error occurred */
if ( ! status ) {
RETURN_FALSE ;
}
if ( tv_sec < 0 ) {
zend_argument_value_error ( 3 , " must be greater than or equal to 0 " ) ;
RETURN_THROWS ( ) ;
}
/* Nanosecond between 0 and 1e9 */
if ( tv_nsec < 0 | | tv_nsec > = 1000000000 ) {
zend_argument_value_error ( 4 , " must be between 0 and 1e9 " ) ;
RETURN_THROWS ( ) ;
}
if ( UNEXPECTED ( tv_sec = = 0 & & tv_nsec = = 0 ) ) {
zend_value_error ( " pcntl_sigtimedwait(): At least one of argument #3 ($seconds) or argument #4 ($nanoseconds) must be greater than 0 " ) ;
RETURN_THROWS ( ) ;
}
errno = 0 ;
siginfo_t siginfo ;
struct timespec timeout ;
timeout . tv_sec = ( time_t ) tv_sec ;
timeout . tv_nsec = tv_nsec ;
int signal_no = sigtimedwait ( & set , & siginfo , & timeout ) ;
if ( signal_no = = - 1 ) {
if ( errno ! = EAGAIN ) {
PCNTL_G ( last_error ) = errno ;
php_error_docref ( NULL , E_WARNING , " %s " , strerror ( errno ) ) ;
}
RETURN_FALSE ;
}
/* sigtimedwait can return 0 on success on some platforms, e.g. NetBSD */
if ( ! signal_no & & siginfo . si_signo ) {
signal_no = siginfo . si_signo ;
}
pcntl_siginfo_to_zval ( signal_no , & siginfo , user_siginfo ) ;
RETURN_LONG ( signal_no ) ;
2016-06-14 06:33:19 +08:00
}
/* }}} */
# endif
2009-03-28 11:21:04 +08:00
2016-06-14 06:33:19 +08:00
static void pcntl_siginfo_to_zval ( int signo , siginfo_t * siginfo , zval * user_siginfo ) /* { { { */
{
2008-07-30 00:59:10 +08:00
if ( signo > 0 & & user_siginfo ) {
2019-01-07 19:28:51 +08:00
user_siginfo = zend_try_array_init ( user_siginfo ) ;
if ( ! user_siginfo ) {
return ;
2008-07-30 00:59:10 +08:00
}
2019-01-07 19:28:51 +08:00
2016-06-14 06:33:19 +08:00
add_assoc_long_ex ( user_siginfo , " signo " , sizeof ( " signo " ) - 1 , siginfo - > si_signo ) ;
add_assoc_long_ex ( user_siginfo , " errno " , sizeof ( " errno " ) - 1 , siginfo - > si_errno ) ;
add_assoc_long_ex ( user_siginfo , " code " , sizeof ( " code " ) - 1 , siginfo - > si_code ) ;
2008-07-30 00:59:10 +08:00
switch ( signo ) {
# ifdef SIGCHLD
case SIGCHLD :
2016-06-14 06:33:19 +08:00
add_assoc_long_ex ( user_siginfo , " status " , sizeof ( " status " ) - 1 , siginfo - > si_status ) ;
2008-08-05 23:12:19 +08:00
# ifdef si_utime
2016-06-14 06:33:19 +08:00
add_assoc_double_ex ( user_siginfo , " utime " , sizeof ( " utime " ) - 1 , siginfo - > si_utime ) ;
2008-08-05 23:12:19 +08:00
# endif
# ifdef si_stime
2016-06-14 06:33:19 +08:00
add_assoc_double_ex ( user_siginfo , " stime " , sizeof ( " stime " ) - 1 , siginfo - > si_stime ) ;
2008-08-05 23:12:19 +08:00
# endif
2016-06-14 06:33:19 +08:00
add_assoc_long_ex ( user_siginfo , " pid " , sizeof ( " pid " ) - 1 , siginfo - > si_pid ) ;
add_assoc_long_ex ( user_siginfo , " uid " , sizeof ( " uid " ) - 1 , siginfo - > si_uid ) ;
break ;
case SIGUSR1 :
case SIGUSR2 :
add_assoc_long_ex ( user_siginfo , " pid " , sizeof ( " pid " ) - 1 , siginfo - > si_pid ) ;
add_assoc_long_ex ( user_siginfo , " uid " , sizeof ( " uid " ) - 1 , siginfo - > si_uid ) ;
2008-07-30 00:59:10 +08:00
break ;
# endif
case SIGILL :
case SIGFPE :
case SIGSEGV :
case SIGBUS :
2016-06-14 06:33:19 +08:00
add_assoc_double_ex ( user_siginfo , " addr " , sizeof ( " addr " ) - 1 , ( zend_long ) siginfo - > si_addr ) ;
2008-07-30 00:59:10 +08:00
break ;
2022-02-24 03:41:19 +08:00
# if defined(SIGPOLL) && !defined(__CYGWIN__)
2008-07-30 00:59:10 +08:00
case SIGPOLL :
2016-06-14 06:33:19 +08:00
add_assoc_long_ex ( user_siginfo , " band " , sizeof ( " band " ) - 1 , siginfo - > si_band ) ;
2008-08-05 23:12:19 +08:00
# ifdef si_fd
2016-06-14 06:33:19 +08:00
add_assoc_long_ex ( user_siginfo , " fd " , sizeof ( " fd " ) - 1 , siginfo - > si_fd ) ;
2008-08-05 23:12:19 +08:00
# endif
2008-07-30 00:59:10 +08:00
break ;
# endif
}
2018-06-28 02:25:11 +08:00
# if defined(SIGRTMIN) && defined(SIGRTMAX)
if ( SIGRTMIN < = signo & & signo < = SIGRTMAX ) {
add_assoc_long_ex ( user_siginfo , " pid " , sizeof ( " pid " ) - 1 , siginfo - > si_pid ) ;
add_assoc_long_ex ( user_siginfo , " uid " , sizeof ( " uid " ) - 1 , siginfo - > si_uid ) ;
}
# endif
2008-07-30 00:59:10 +08:00
}
}
/* }}} */
# endif
2003-02-18 09:41:06 +08:00
# ifdef HAVE_GETPRIORITY
2020-07-01 21:32:55 +08:00
/* {{{ Get the priority of any process */
2003-02-18 09:41:06 +08:00
PHP_FUNCTION ( pcntl_getpriority )
{
2014-08-26 01:24:55 +08:00
zend_long who = PRIO_PROCESS ;
2020-06-08 17:10:56 +08:00
zend_long pid ;
2021-01-15 19:30:54 +08:00
bool pid_is_null = 1 ;
2003-02-18 09:41:06 +08:00
int pri ;
2015-01-03 17:22:58 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 0 , 2 )
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL ( pid , pid_is_null )
Z_PARAM_LONG ( who )
ZEND_PARSE_PARAMETERS_END ( ) ;
2003-02-18 09:41:06 +08:00
2015-01-03 17:22:58 +08:00
/* needs to be cleared, since any returned value is valid */
2003-02-18 09:41:06 +08:00
errno = 0 ;
2022-07-23 00:38:59 +08:00
pid = pid_is_null ? getpid ( ) : pid ;
pri = getpriority ( who , pid ) ;
2003-02-18 09:41:06 +08:00
if ( errno ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2003-02-18 09:41:06 +08:00
switch ( errno ) {
case ESRCH :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error %d: No process was located using the given parameters " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
case EINVAL :
2022-07-23 00:38:59 +08:00
# ifdef PRIO_DARWIN_BG
if ( who ! = PRIO_PGRP & & who ! = PRIO_USER & & who ! = PRIO_PROCESS & & who ! = PRIO_DARWIN_THREAD ) {
zend_argument_value_error ( 2 , " must be one of PRIO_PGRP, PRIO_USER, PRIO_PROCESS or PRIO_DARWIN_THREAD " ) ;
RETURN_THROWS ( ) ;
} else if ( who = = PRIO_DARWIN_THREAD & & pid ! = 0 ) {
zend_argument_value_error ( 1 , " must be 0 (zero) if PRIO_DARWIN_THREAD is provided as second parameter " ) ;
RETURN_THROWS ( ) ;
} else {
zend_argument_value_error ( 1 , " is not a valid process, process group, or user ID " ) ;
RETURN_THROWS ( ) ;
}
# else
2020-08-18 04:37:20 +08:00
zend_argument_value_error ( 2 , " must be one of PRIO_PGRP, PRIO_USER, or PRIO_PROCESS " ) ;
RETURN_THROWS ( ) ;
2022-07-23 00:38:59 +08:00
# endif
2003-02-18 09:41:06 +08:00
default :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Unknown error %d has occurred " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
}
RETURN_FALSE ;
}
2014-08-26 01:24:55 +08:00
RETURN_LONG ( pri ) ;
2003-02-18 09:41:06 +08:00
}
/* }}} */
# endif
# ifdef HAVE_SETPRIORITY
2020-07-01 21:32:55 +08:00
/* {{{ Change the priority of any process */
2003-02-18 09:41:06 +08:00
PHP_FUNCTION ( pcntl_setpriority )
{
2014-08-26 01:24:55 +08:00
zend_long who = PRIO_PROCESS ;
2020-06-08 17:10:56 +08:00
zend_long pid ;
2021-01-15 19:30:54 +08:00
bool pid_is_null = 1 ;
2014-08-26 01:24:55 +08:00
zend_long pri ;
2003-02-18 09:41:06 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 3 )
Z_PARAM_LONG ( pri )
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL ( pid , pid_is_null )
Z_PARAM_LONG ( who )
ZEND_PARSE_PARAMETERS_END ( ) ;
2003-02-18 09:41:06 +08:00
2022-07-23 00:38:59 +08:00
pid = pid_is_null ? getpid ( ) : pid ;
if ( setpriority ( who , pid , pri ) ) {
2010-11-02 04:10:17 +08:00
PCNTL_G ( last_error ) = errno ;
2003-02-18 09:41:06 +08:00
switch ( errno ) {
case ESRCH :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error %d: No process was located using the given parameters " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
case EINVAL :
2022-07-23 00:38:59 +08:00
# ifdef PRIO_DARWIN_BG
if ( who ! = PRIO_PGRP & & who ! = PRIO_USER & & who ! = PRIO_PROCESS & & who ! = PRIO_DARWIN_THREAD ) {
zend_argument_value_error ( 3 , " must be one of PRIO_PGRP, PRIO_USER, PRIO_PROCESS or PRIO_DARWIN_THREAD " ) ;
RETURN_THROWS ( ) ;
} else if ( who = = PRIO_DARWIN_THREAD & & pid ! = 0 ) {
zend_argument_value_error ( 2 , " must be 0 (zero) if PRIO_DARWIN_THREAD is provided as second parameter " ) ;
RETURN_THROWS ( ) ;
} else if ( who = = PRIO_DARWIN_THREAD & & pid = = 0 & & ( pri ! = 0 & & pri ! = PRIO_DARWIN_BG ) ) {
zend_argument_value_error ( 1 , " must be either 0 (zero) or PRIO_DARWIN_BG, for mode PRIO_DARWIN_THREAD " ) ;
RETURN_THROWS ( ) ;
} else {
zend_argument_value_error ( 2 , " is not a valid process, process group, or user ID " ) ;
RETURN_THROWS ( ) ;
}
# else
2020-08-18 04:37:20 +08:00
zend_argument_value_error ( 3 , " must be one of PRIO_PGRP, PRIO_USER, or PRIO_PROCESS " ) ;
RETURN_THROWS ( ) ;
2022-07-23 00:38:59 +08:00
# endif
2003-02-18 09:41:06 +08:00
case EPERM :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error %d: A process was located, but neither its effective nor real user ID matched the effective user ID of the caller " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
case EACCES :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Error %d: Only a super user may attempt to increase the process priority " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
default :
2014-12-14 06:06:14 +08:00
php_error_docref ( NULL , E_WARNING , " Unknown error %d has occurred " , errno ) ;
2003-02-18 09:41:06 +08:00
break ;
}
RETURN_FALSE ;
}
2015-01-03 17:22:58 +08:00
2003-02-18 09:41:06 +08:00
RETURN_TRUE ;
}
/* }}} */
# endif
2020-07-01 21:32:55 +08:00
/* {{{ Retrieve the error number set by the last pcntl function which failed. */
2010-11-02 04:10:17 +08:00
PHP_FUNCTION ( pcntl_get_last_error )
{
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_NONE ( ) ;
2019-08-27 23:25:19 +08:00
RETURN_LONG ( PCNTL_G ( last_error ) ) ;
2010-11-02 04:10:17 +08:00
}
/* }}} */
2020-07-01 21:32:55 +08:00
/* {{{ Retrieve the system error message associated with the given errno. */
2010-11-02 04:10:17 +08:00
PHP_FUNCTION ( pcntl_strerror )
{
2019-08-27 23:25:19 +08:00
zend_long error ;
2010-11-02 04:10:17 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( error )
ZEND_PARSE_PARAMETERS_END ( ) ;
2010-11-02 04:10:17 +08:00
2019-08-27 23:25:19 +08:00
RETURN_STRING ( strerror ( error ) ) ;
2010-11-02 04:10:17 +08:00
}
/* }}} */
2001-06-26 01:56:23 +08:00
/* Our custom signal handler that calls the appropriate php_function */
2016-06-14 06:33:19 +08:00
# ifdef HAVE_STRUCT_SIGINFO_T
static void pcntl_signal_handler ( int signo , siginfo_t * siginfo , void * context )
# else
2001-06-20 05:42:57 +08:00
static void pcntl_signal_handler ( int signo )
2016-06-14 06:33:19 +08:00
# endif
2001-06-20 05:42:57 +08:00
{
2023-08-03 03:08:52 +08:00
struct php_pcntl_pending_signal * psig = PCNTL_G ( spares ) ;
if ( ! psig ) {
2005-05-07 22:58:12 +08:00
/* oops, too many signals for us to track, so we'll forget about this one */
return ;
}
2023-08-03 03:08:52 +08:00
PCNTL_G ( spares ) = psig - > next ;
2005-05-07 22:58:12 +08:00
2023-08-03 03:08:52 +08:00
psig - > signo = signo ;
psig - > next = NULL ;
2005-05-07 22:58:12 +08:00
2016-06-14 06:33:19 +08:00
# ifdef HAVE_STRUCT_SIGINFO_T
2023-08-03 03:08:52 +08:00
psig - > siginfo = * siginfo ;
2016-06-14 06:33:19 +08:00
# endif
2005-05-07 22:58:12 +08:00
/* the head check is important, as the tick handler cannot atomically clear both
* the head and tail */
if ( PCNTL_G ( head ) & & PCNTL_G ( tail ) ) {
2023-08-03 03:08:52 +08:00
PCNTL_G ( tail ) - > next = psig ;
2005-05-07 22:58:12 +08:00
} else {
2023-08-03 03:08:52 +08:00
PCNTL_G ( head ) = psig ;
2001-06-20 05:42:57 +08:00
}
2005-05-07 22:58:12 +08:00
PCNTL_G ( tail ) = psig ;
2014-06-11 23:34:34 +08:00
PCNTL_G ( pending_signals ) = 1 ;
2016-07-06 18:11:47 +08:00
if ( PCNTL_G ( async_signals ) ) {
2022-06-01 23:43:25 +08:00
zend_atomic_bool_store_ex ( & EG ( vm_interrupt ) , true ) ;
2016-07-06 18:11:47 +08:00
}
2001-06-20 05:42:57 +08:00
}
2023-02-09 06:42:44 +08:00
void pcntl_signal_dispatch ( void )
2001-07-30 16:24:42 +08:00
{
2016-06-14 06:33:19 +08:00
zval params [ 2 ] , * handle , retval ;
2005-05-07 22:58:12 +08:00
struct php_pcntl_pending_signal * queue , * next ;
2010-11-02 06:29:25 +08:00
sigset_t mask ;
sigset_t old_mask ;
2014-06-11 23:34:34 +08:00
if ( ! PCNTL_G ( pending_signals ) ) {
return ;
}
2015-01-03 17:22:58 +08:00
2010-11-02 06:29:25 +08:00
/* Mask all signals */
sigfillset ( & mask ) ;
sigprocmask ( SIG_BLOCK , & mask , & old_mask ) ;
2001-06-20 05:42:57 +08:00
2016-06-14 06:33:19 +08:00
/* Bail if the queue is empty or if we are already playing the queue */
if ( ! PCNTL_G ( head ) | | PCNTL_G ( processing_signal_queue ) ) {
2010-11-02 06:40:29 +08:00
sigprocmask ( SIG_SETMASK , & old_mask , NULL ) ;
2001-06-20 05:42:57 +08:00
return ;
2010-11-02 06:40:29 +08:00
}
2001-06-20 05:42:57 +08:00
2022-07-17 02:05:16 +08:00
/* Prevent switching fibers when handling signals */
zend_fiber_switch_block ( ) ;
2002-08-22 12:20:10 +08:00
/* Prevent reentrant handler calls */
2002-03-17 06:31:57 +08:00
PCNTL_G ( processing_signal_queue ) = 1 ;
2005-05-07 22:58:12 +08:00
queue = PCNTL_G ( head ) ;
PCNTL_G ( head ) = NULL ; /* simple stores are atomic */
2015-01-03 17:22:58 +08:00
2001-06-20 05:42:57 +08:00
/* Allocate */
2005-05-07 22:58:12 +08:00
while ( queue ) {
2014-05-06 18:23:56 +08:00
if ( ( handle = zend_hash_index_find ( & PCNTL_G ( php_signal_table ) , queue - > signo ) ) ! = NULL ) {
2016-07-06 20:45:20 +08:00
if ( Z_TYPE_P ( handle ) ! = IS_LONG ) {
ZVAL_NULL ( & retval ) ;
2016-06-14 06:33:19 +08:00
ZVAL_LONG ( & params [ 0 ] , queue - > signo ) ;
# ifdef HAVE_STRUCT_SIGINFO_T
2017-01-15 10:51:33 +08:00
array_init ( & params [ 1 ] ) ;
pcntl_siginfo_to_zval ( queue - > signo , & queue - > siginfo , & params [ 1 ] ) ;
2016-06-14 06:33:19 +08:00
# else
ZVAL_NULL ( & params [ 1 ] ) ;
# endif
2016-07-06 20:45:20 +08:00
/* Call php signal handler - Note that we do not report errors, and we ignore the return value */
/* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
2019-03-10 15:16:04 +08:00
call_user_function ( NULL , NULL , handle , & retval , 2 , params ) ;
2016-07-06 20:45:20 +08:00
zval_ptr_dtor ( & retval ) ;
2018-05-29 22:58:06 +08:00
# ifdef HAVE_STRUCT_SIGINFO_T
2016-06-14 06:33:19 +08:00
zval_ptr_dtor ( & params [ 1 ] ) ;
2018-05-29 22:58:06 +08:00
# endif
2016-07-06 20:45:20 +08:00
}
2001-06-20 05:42:57 +08:00
}
2002-05-07 07:01:46 +08:00
2005-05-07 22:58:12 +08:00
next = queue - > next ;
queue - > next = PCNTL_G ( spares ) ;
PCNTL_G ( spares ) = queue ;
queue = next ;
2001-06-20 05:42:57 +08:00
}
2014-06-11 23:34:34 +08:00
PCNTL_G ( pending_signals ) = 0 ;
2001-06-20 05:42:57 +08:00
/* Re-enable queue */
2002-03-17 06:31:57 +08:00
PCNTL_G ( processing_signal_queue ) = 0 ;
2015-01-03 17:22:58 +08:00
2022-07-17 02:05:16 +08:00
/* Re-enable fiber switching */
zend_fiber_switch_unblock ( ) ;
2010-11-02 06:29:25 +08:00
/* return signal mask to previous state */
sigprocmask ( SIG_SETMASK , & old_mask , NULL ) ;
2001-06-20 05:42:57 +08:00
}
2021-05-13 01:54:57 +08:00
static void pcntl_signal_dispatch_tick_function ( int dummy_int , void * dummy_pointer )
{
return pcntl_signal_dispatch ( ) ;
}
2020-07-01 21:32:55 +08:00
/* {{{ Enable/disable asynchronous signal handling and return the old setting. */
2016-07-06 18:11:47 +08:00
PHP_FUNCTION ( pcntl_async_signals )
{
2021-01-15 19:30:54 +08:00
bool on , on_is_null = 1 ;
2005-05-07 22:58:12 +08:00
2021-12-21 14:17:12 +08:00
ZEND_PARSE_PARAMETERS_START ( 0 , 1 )
Z_PARAM_OPTIONAL
Z_PARAM_BOOL_OR_NULL ( on , on_is_null )
ZEND_PARSE_PARAMETERS_END ( ) ;
2020-06-08 17:10:56 +08:00
if ( on_is_null ) {
RETURN_BOOL ( PCNTL_G ( async_signals ) ) ;
}
2016-07-06 18:11:47 +08:00
RETVAL_BOOL ( PCNTL_G ( async_signals ) ) ;
PCNTL_G ( async_signals ) = on ;
}
/* }}} */
2019-01-22 07:56:43 +08:00
# ifdef HAVE_UNSHARE
2020-07-01 21:32:55 +08:00
/* {{{ disassociate parts of the process execution context */
2019-01-22 07:56:43 +08:00
PHP_FUNCTION ( pcntl_unshare )
{
zend_long flags ;
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
Z_PARAM_LONG ( flags )
ZEND_PARSE_PARAMETERS_END ( ) ;
2020-08-18 04:37:20 +08:00
if ( unshare ( flags ) = = - 1 ) {
2019-01-22 07:56:43 +08:00
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
# ifdef EINVAL
case EINVAL :
2024-04-03 06:26:07 +08:00
zend_argument_value_error ( 1 , " must be a combination of CLONE_* flags, or at least one flag is unsupported by the kernel " ) ;
2020-08-18 04:37:20 +08:00
RETURN_THROWS ( ) ;
2019-01-22 07:56:43 +08:00
break ;
# endif
# ifdef ENOMEM
case ENOMEM :
php_error_docref ( NULL , E_WARNING , " Error %d: Insufficient memory for unshare " , errno ) ;
break ;
# endif
# ifdef EPERM
case EPERM :
php_error_docref ( NULL , E_WARNING , " Error %d: No privilege to use these flags " , errno ) ;
break ;
# endif
# ifdef ENOSPC
case ENOSPC :
php_error_docref ( NULL , E_WARNING , " Error %d: Reached the maximum nesting limit for one of the specified namespaces " , errno ) ;
break ;
# endif
# ifdef EUSERS
case EUSERS :
php_error_docref ( NULL , E_WARNING , " Error %d: Reached the maximum nesting limit for the user namespace " , errno ) ;
break ;
# endif
default :
php_error_docref ( NULL , E_WARNING , " Unknown error %d has occurred " , errno ) ;
break ;
}
RETURN_FALSE ;
}
RETURN_TRUE ;
}
/* }}} */
# endif
2021-05-23 18:02:33 +08:00
# ifdef HAVE_RFORK
2021-05-31 19:36:49 +08:00
/* {{{ proto bool pcntl_rfork(int flags [, int signal])
2021-05-23 18:02:33 +08:00
More control over the process creation is given over fork / vfork . */
PHP_FUNCTION ( pcntl_rfork )
{
2021-06-01 00:04:18 +08:00
zend_long flags ;
zend_long csignal = 0 ;
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 ) {
zend_argument_value_error ( 1 , " must not include RFMEM value, not allowed within this context " ) ;
RETURN_THROWS ( ) ;
}
if ( ( flags & RFSIGSHARE ) ! = 0 ) {
zend_argument_value_error ( 1 , " must not include RFSIGSHARE value, not allowed within this context " ) ;
RETURN_THROWS ( ) ;
}
if ( ( flags & ( RFFDG | RFCFDG ) ) = = ( RFFDG | RFCFDG ) ) {
zend_argument_value_error ( 1 , " must not include both RFFDG and RFCFDG, because these flags are mutually exclusive " ) ;
RETURN_THROWS ( ) ;
}
/* A new pid is required */
if ( ! ( flags & ( RFPROC ) ) ) {
flags | = RFPROC ;
}
2022-01-10 01:10:21 +08:00
# ifdef RFTSIGZMB
2021-06-01 00:04:18 +08:00
if ( ( flags & RFTSIGZMB ) ! = 0 ) {
flags | = RFTSIGFLAGS ( csignal ) ;
}
2022-01-10 01:10:21 +08:00
# endif
2021-06-01 00:04:18 +08:00
pid = rfork ( flags ) ;
if ( pid = = - 1 ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
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 ) ;
2021-05-23 18:02:33 +08:00
}
# endif
/* }}} */
2021-11-30 22:47:14 +08:00
# ifdef HAVE_FORKX
/* {{{ proto bool pcntl_forkx(int flags)
More elaborated version of fork with the following settings .
FORK_WAITPID : forbid the parent process to wait for multiple pid but one only
FORK_NOSIGCHLD : SIGCHLD signal ignored when the child terminates */
PHP_FUNCTION ( pcntl_forkx )
{
zend_long flags ;
pid_t pid ;
2023-05-07 00:26:57 +08:00
ZEND_PARSE_PARAMETERS_START ( 1 , 1 )
2021-11-30 22:47:14 +08:00
Z_PARAM_LONG ( flags )
ZEND_PARSE_PARAMETERS_END ( ) ;
if ( flags < FORK_NOSIGCHLD | | flags > FORK_WAITPID ) {
zend_argument_value_error ( 1 , " must be FORK_NOSIGCHLD or FORK_WAITPID " ) ;
RETURN_THROWS ( ) ;
}
pid = forkx ( flags ) ;
if ( pid = = - 1 ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
case EAGAIN :
php_error_docref ( NULL , E_WARNING , " Maximum process creations limit reached \n " ) ;
break ;
case EPERM :
php_error_docref ( NULL , E_WARNING , " Calling process not having the proper privileges \n " ) ;
break ;
case ENOMEM :
php_error_docref ( NULL , E_WARNING , " No swap space left \n " ) ;
break ;
default :
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
}
}
RETURN_LONG ( ( zend_long ) pid ) ;
}
# endif
/* }}} */
2024-04-04 01:59:40 +08:00
# ifdef HAVE_PIDFD_OPEN
// The `pidfd_open` syscall is available since 5.3
// and `setns` since 3.0.
PHP_FUNCTION ( pcntl_setns )
{
zend_long pid , nstype = CLONE_NEWNET ;
bool pid_is_null = 1 ;
int fd , ret ;
ZEND_PARSE_PARAMETERS_START ( 0 , 2 )
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL ( pid , pid_is_null )
Z_PARAM_LONG ( nstype )
ZEND_PARSE_PARAMETERS_END ( ) ;
pid = pid_is_null ? getpid ( ) : pid ;
fd = syscall ( SYS_pidfd_open , pid , 0 ) ;
if ( errno ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
case EINVAL :
case ESRCH :
2024-04-05 04:05:35 +08:00
zend_argument_value_error ( 1 , " is not a valid process ( " ZEND_LONG_FMT " ) " , pid ) ;
2024-04-04 01:59:40 +08:00
RETURN_THROWS ( ) ;
case ENFILE :
php_error_docref ( NULL , E_WARNING , " Error %d: File descriptors per-process limit reached " , errno ) ;
break ;
case ENODEV :
php_error_docref ( NULL , E_WARNING , " Error %d: Anonymous inode fs unsupported " , errno ) ;
break ;
case ENOMEM :
php_error_docref ( NULL , E_WARNING , " Error %d: Insufficient memory for pidfd_open " , errno ) ;
break ;
default :
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
}
RETURN_FALSE ;
}
ret = setns ( fd , ( int ) nstype ) ;
close ( fd ) ;
if ( ret = = - 1 ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
case ESRCH :
2024-04-05 04:05:35 +08:00
zend_argument_value_error ( 1 , " process no longer available ( " ZEND_LONG_FMT " ) " , pid ) ;
2024-04-04 01:59:40 +08:00
RETURN_THROWS ( ) ;
case EINVAL :
zend_argument_value_error ( 2 , " is an invalid nstype (%d) " , nstype ) ;
RETURN_THROWS ( ) ;
case EPERM :
php_error_docref ( NULL , E_WARNING , " Error %d: No required capability for this process " , errno ) ;
break ;
default :
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
}
RETURN_FALSE ;
} else {
RETURN_TRUE ;
}
}
# endif
2024-04-06 04:37:59 +08:00
# ifdef HAVE_SCHED_SETAFFINITY
PHP_FUNCTION ( pcntl_getcpuaffinity )
{
zend_long pid ;
bool pid_is_null = 1 ;
cpu_set_t mask ;
ZEND_PARSE_PARAMETERS_START ( 0 , 1 )
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL ( pid , pid_is_null )
ZEND_PARSE_PARAMETERS_END ( ) ;
// 0 == getpid in this context, we're just saving a syscall
pid = pid_is_null ? 0 : pid ;
CPU_ZERO ( & mask ) ;
if ( sched_getaffinity ( pid , sizeof ( mask ) , & mask ) ! = 0 ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
case ESRCH :
zend_argument_value_error ( 1 , " invalid process ( " ZEND_LONG_FMT " ) " , pid ) ;
RETURN_THROWS ( ) ;
case EPERM :
php_error_docref ( NULL , E_WARNING , " Calling process not having the proper privileges " ) ;
break ;
default :
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
}
RETURN_FALSE ;
}
zend_ulong maxcpus = ( zend_ulong ) sysconf ( _SC_NPROCESSORS_CONF ) ;
array_init ( return_value ) ;
for ( zend_ulong i = 0 ; i < maxcpus ; i + + ) {
if ( CPU_ISSET ( i , & mask ) ) {
add_next_index_long ( return_value , i ) ;
}
}
}
PHP_FUNCTION ( pcntl_setcpuaffinity )
{
zend_long pid ;
bool pid_is_null = 1 ;
cpu_set_t mask ;
zval * hmask = NULL , * ncpu ;
ZEND_PARSE_PARAMETERS_START ( 0 , 2 )
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL ( pid , pid_is_null )
Z_PARAM_ARRAY ( hmask )
ZEND_PARSE_PARAMETERS_END ( ) ;
if ( ! hmask | | zend_hash_num_elements ( Z_ARRVAL_P ( hmask ) ) = = 0 ) {
zend_argument_value_error ( 2 , " must not be empty " ) ;
RETURN_THROWS ( ) ;
}
// 0 == getpid in this context, we're just saving a syscall
pid = pid_is_null ? 0 : pid ;
zend_ulong maxcpus = ( zend_ulong ) sysconf ( _SC_NPROCESSORS_CONF ) ;
CPU_ZERO ( & mask ) ;
ZEND_HASH_FOREACH_VAL ( Z_ARRVAL_P ( hmask ) , ncpu ) {
ZVAL_DEREF ( ncpu ) ;
zend_long cpu ;
if ( Z_TYPE_P ( ncpu ) ! = IS_LONG ) {
if ( Z_TYPE_P ( ncpu ) = = IS_STRING ) {
zend_ulong tmp ;
if ( ! ZEND_HANDLE_NUMERIC ( Z_STR_P ( ncpu ) , tmp ) ) {
zend_argument_value_error ( 2 , " cpu id invalid value (%s) " , ZSTR_VAL ( Z_STR_P ( ncpu ) ) ) ;
RETURN_THROWS ( ) ;
}
cpu = ( zend_long ) tmp ;
} else {
zend_string * wcpu = zval_get_string_func ( ncpu ) ;
zend_argument_value_error ( 2 , " cpu id invalid type (%s) " , ZSTR_VAL ( wcpu ) ) ;
zend_string_release ( wcpu ) ;
RETURN_THROWS ( ) ;
}
} else {
cpu = Z_LVAL_P ( ncpu ) ;
}
if ( cpu < 0 | | cpu > = maxcpus ) {
zend_argument_value_error ( 2 , " cpu id must be between 0 and " ZEND_ULONG_FMT " ( " ZEND_LONG_FMT " ) " , maxcpus , cpu ) ;
RETURN_THROWS ( ) ;
}
if ( ! CPU_ISSET ( cpu , & mask ) ) {
CPU_SET ( cpu , & mask ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
if ( sched_setaffinity ( pid , sizeof ( mask ) , & mask ) ! = 0 ) {
PCNTL_G ( last_error ) = errno ;
switch ( errno ) {
case ESRCH :
zend_argument_value_error ( 1 , " invalid process ( " ZEND_LONG_FMT " ) " , pid ) ;
RETURN_THROWS ( ) ;
case EPERM :
php_error_docref ( NULL , E_WARNING , " Calling process not having the proper privileges " ) ;
break ;
default :
php_error_docref ( NULL , E_WARNING , " Error %d " , errno ) ;
}
RETURN_FALSE ;
} else {
RETURN_TRUE ;
}
}
# endif
2016-07-06 18:11:47 +08:00
static void pcntl_interrupt_function ( zend_execute_data * execute_data )
{
pcntl_signal_dispatch ( ) ;
if ( orig_interrupt_function ) {
orig_interrupt_function ( execute_data ) ;
}
}