diff options
Diffstat (limited to 'ext/pcntl')
-rw-r--r-- | ext/pcntl/config.m4 | 18 | ||||
-rw-r--r-- | ext/pcntl/pcntl.c | 212 | ||||
-rw-r--r-- | ext/pcntl/php_pcntl.h | 12 | ||||
-rw-r--r-- | ext/pcntl/php_signal.c | 25 | ||||
-rw-r--r-- | ext/pcntl/php_signal.h | 6 | ||||
-rw-r--r-- | ext/pcntl/tests/async_signals.phpt | 25 | ||||
-rw-r--r-- | ext/pcntl/tests/bug73783.phpt | 28 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_signal.phpt | 7 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_signal_get_handler.phpt | 30 |
9 files changed, 295 insertions, 68 deletions
diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index 70e0aeb008..8e4dc41f33 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -10,5 +10,21 @@ if test "$PHP_PCNTL" != "no"; then AC_CHECK_FUNCS(waitpid, [ AC_DEFINE(HAVE_WAITPID,1,[ ]) ], [ AC_MSG_ERROR(pcntl: waitpid() not supported by this platform) ]) AC_CHECK_FUNCS(sigaction, [ AC_DEFINE(HAVE_SIGACTION,1,[ ]) ], [ AC_MSG_ERROR(pcntl: sigaction() not supported by this platform) ]) AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigprocmask sigwaitinfo sigtimedwait]) - PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli) + + AC_MSG_CHECKING([for siginfo_t]) + AC_TRY_COMPILE([ + #include <signal.h> + #ifdef HAVE_SIGINFO_H + #include <siginfo.h> + #endif + ],[ + siginfo_t info; + ],[ + AC_MSG_RESULT([yes]) + PCNTL_CFLAGS="-DHAVE_STRUCT_SIGINFO_T" + ], [ + AC_MSG_RESULT([no]) + ]) + + PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli, $PCNTL_CFLAGS) fi diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 561815f5cc..886099c573 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2017 The PHP Group | + | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -72,12 +72,18 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2) ZEND_ARG_INFO(0, restart_syscalls) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal_get_handler, 0, 0, 1) + ZEND_ARG_INFO(0, signo) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2) ZEND_ARG_INFO(0, how) ZEND_ARG_INFO(0, set) ZEND_ARG_INFO(1, oldset) ZEND_END_ARG_INFO() +#ifdef HAVE_STRUCT_SIGINFO_T +# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1) ZEND_ARG_INFO(0, set) ZEND_ARG_INFO(1, info) @@ -89,6 +95,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1) ZEND_ARG_INFO(0, seconds) ZEND_ARG_INFO(0, nanoseconds) ZEND_END_ARG_INFO() +# endif +#endif ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1) ZEND_ARG_INFO(0, status) @@ -148,6 +156,10 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1) ZEND_ARG_INFO(0, errno) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_async_signals, 0, 0, 1) + ZEND_ARG_INFO(0, on) +ZEND_END_ARG_INFO() /* }}} */ const zend_function_entry pcntl_functions[] = { @@ -155,6 +167,7 @@ const zend_function_entry pcntl_functions[] = { PHP_FE(pcntl_waitpid, arginfo_pcntl_waitpid) PHP_FE(pcntl_wait, arginfo_pcntl_wait) PHP_FE(pcntl_signal, arginfo_pcntl_signal) + PHP_FE(pcntl_signal_get_handler, arginfo_pcntl_signal_get_handler) PHP_FE(pcntl_signal_dispatch, arginfo_pcntl_void) PHP_FE(pcntl_wifexited, arginfo_pcntl_wifexited) PHP_FE(pcntl_wifstopped, arginfo_pcntl_wifstopped) @@ -176,13 +189,16 @@ const zend_function_entry pcntl_functions[] = { #ifdef HAVE_SIGPROCMASK PHP_FE(pcntl_sigprocmask, arginfo_pcntl_sigprocmask) #endif -#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT +#ifdef HAVE_STRUCT_SIGINFO_T +# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT PHP_FE(pcntl_sigwaitinfo, arginfo_pcntl_sigwaitinfo) PHP_FE(pcntl_sigtimedwait, arginfo_pcntl_sigtimedwait) +# endif #endif #ifdef HAVE_WCONTINUED PHP_FE(pcntl_wifcontinued, arginfo_pcntl_wifcontinued) #endif + PHP_FE(pcntl_async_signals, arginfo_pcntl_async_signals) PHP_FE_END }; @@ -207,8 +223,16 @@ zend_module_entry pcntl_module_entry = { ZEND_GET_MODULE(pcntl) #endif +static void (*orig_interrupt_function)(zend_execute_data *execute_data); + +#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 static void pcntl_signal_handler(int); +#endif static void pcntl_signal_dispatch(); +static void pcntl_interrupt_function(zend_execute_data *execute_data); void php_register_signal_constants(INIT_FUNC_ARGS) { @@ -506,6 +530,7 @@ PHP_RINIT_FUNCTION(pcntl) { zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0); PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL; + PCNTL_G(async_signals) = 0; return SUCCESS; } @@ -514,6 +539,8 @@ PHP_MINIT_FUNCTION(pcntl) php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU); php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU); php_add_tick_function(pcntl_signal_dispatch, NULL); + orig_interrupt_function = zend_interrupt_function; + zend_interrupt_function = pcntl_interrupt_function; return SUCCESS; } @@ -734,9 +761,10 @@ PHP_FUNCTION(pcntl_wifexited) return; } - if (WIFEXITED(status_word)) + if (WIFEXITED((int)status_word)) RETURN_TRUE; #endif + RETURN_FALSE; } /* }}} */ @@ -752,7 +780,7 @@ PHP_FUNCTION(pcntl_wifstopped) return; } - if (WIFSTOPPED(status_word)) + if (WIFSTOPPED((int)status_word)) RETURN_TRUE; #endif RETURN_FALSE; @@ -770,7 +798,7 @@ PHP_FUNCTION(pcntl_wifsignaled) return; } - if (WIFSIGNALED(status_word)) + if (WIFSIGNALED((int)status_word)) RETURN_TRUE; #endif RETURN_FALSE; @@ -787,7 +815,7 @@ PHP_FUNCTION(pcntl_wifcontinued) return; } - if (WIFCONTINUED(status_word)) + if (WIFCONTINUED((int)status_word)) RETURN_TRUE; #endif RETURN_FALSE; @@ -806,7 +834,7 @@ PHP_FUNCTION(pcntl_wexitstatus) return; } - RETURN_LONG(WEXITSTATUS(status_word)); + RETURN_LONG(WEXITSTATUS((int)status_word)); #else RETURN_FALSE; #endif @@ -824,7 +852,7 @@ PHP_FUNCTION(pcntl_wtermsig) return; } - RETURN_LONG(WTERMSIG(status_word)); + RETURN_LONG(WTERMSIG((int)status_word)); #else RETURN_FALSE; #endif @@ -842,7 +870,7 @@ PHP_FUNCTION(pcntl_wstopsig) return; } - RETURN_LONG(WSTOPSIG(status_word)); + RETURN_LONG(WSTOPSIG((int)status_word)); #else RETURN_FALSE; #endif @@ -981,12 +1009,12 @@ PHP_FUNCTION(pcntl_signal) php_error_docref(NULL, E_WARNING, "Invalid value for handle argument specified"); RETURN_FALSE; } - if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) { + if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == (Sigfunc *)SIG_ERR) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error assigning signal"); RETURN_FALSE; } - zend_hash_index_del(&PCNTL_G(php_signal_table), signo); + zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle); RETURN_TRUE; } @@ -1003,7 +1031,7 @@ PHP_FUNCTION(pcntl_signal) if (Z_REFCOUNTED_P(handle)) Z_ADDREF_P(handle); } - if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) { + if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == (Sigfunc *)SIG_ERR) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error assigning signal"); RETURN_FALSE; @@ -1012,6 +1040,29 @@ PHP_FUNCTION(pcntl_signal) } /* }}} */ +/* {{{ proto bool pcntl_signal_get_handler(int signo) + Gets signal handler */ +PHP_FUNCTION(pcntl_signal_get_handler) +{ + zval *prev_handle; + zend_long signo; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &signo) == FAILURE) { + return; + } + + if (signo < 1 || signo > 32) { + php_error_docref(NULL, E_WARNING, "Invalid signal"); + RETURN_FALSE; + } + + if ((prev_handle = zend_hash_index_find(&PCNTL_G(php_signal_table), signo)) != NULL) { + RETURN_ZVAL(prev_handle, 1, 0); + } else { + RETURN_LONG((zend_long)SIG_DFL); + } +} + /* {{{ proto bool pcntl_signal_dispatch() Dispatch signals to signal handlers */ PHP_FUNCTION(pcntl_signal_dispatch) @@ -1075,7 +1126,8 @@ PHP_FUNCTION(pcntl_sigprocmask) /* }}} */ #endif -#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT +#ifdef HAVE_STRUCT_SIGINFO_T +# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */ { zval *user_set, *user_signo, *user_siginfo = NULL; @@ -1129,7 +1181,30 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{ if (!signo && siginfo.si_signo) { signo = siginfo.si_signo; } + pcntl_siginfo_to_zval(signo, &siginfo, user_siginfo); + RETURN_LONG(signo); +} +/* }}} */ + +/* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo]) + Synchronously wait for queued signals */ +PHP_FUNCTION(pcntl_sigwaitinfo) +{ + pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]]) + Wait for queued signals */ +PHP_FUNCTION(pcntl_sigtimedwait) +{ + pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ +# endif +static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */ +{ if (signo > 0 && user_siginfo) { if (Z_TYPE_P(user_siginfo) != IS_ARRAY) { zval_dtor(user_siginfo); @@ -1137,57 +1212,44 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{ } else { zend_hash_clean(Z_ARRVAL_P(user_siginfo)); } - 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); + 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); switch(signo) { #ifdef SIGCHLD case SIGCHLD: - add_assoc_long_ex(user_siginfo, "status", sizeof("status")-1, siginfo.si_status); + add_assoc_long_ex(user_siginfo, "status", sizeof("status")-1, siginfo->si_status); # ifdef si_utime - add_assoc_double_ex(user_siginfo, "utime", sizeof("utime")-1, siginfo.si_utime); + add_assoc_double_ex(user_siginfo, "utime", sizeof("utime")-1, siginfo->si_utime); # endif # ifdef si_stime - add_assoc_double_ex(user_siginfo, "stime", sizeof("stime")-1, siginfo.si_stime); + add_assoc_double_ex(user_siginfo, "stime", sizeof("stime")-1, siginfo->si_stime); # endif - 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); + 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); break; #endif case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: - add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo.si_addr); + add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr); break; #ifdef SIGPOLL case SIGPOLL: - add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo.si_band); + add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo->si_band); # ifdef si_fd - add_assoc_long_ex(user_siginfo, "fd", sizeof("fd")-1, siginfo.si_fd); + add_assoc_long_ex(user_siginfo, "fd", sizeof("fd")-1, siginfo->si_fd); # endif break; #endif } } - - RETURN_LONG(signo); -} -/* }}} */ - -/* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo]) - Synchronously wait for queued signals */ -PHP_FUNCTION(pcntl_sigwaitinfo) -{ - pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); -} -/* }}} */ - -/* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]]) - Wait for queued signals */ -PHP_FUNCTION(pcntl_sigtimedwait) -{ - pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ #endif @@ -1294,7 +1356,11 @@ PHP_FUNCTION(pcntl_strerror) /* }}} */ /* Our custom signal handler that calls the appropriate php_function */ +#ifdef HAVE_STRUCT_SIGINFO_T +static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context) +#else static void pcntl_signal_handler(int signo) +#endif { struct php_pcntl_pending_signal *psig; @@ -1308,6 +1374,10 @@ static void pcntl_signal_handler(int signo) psig->signo = signo; psig->next = NULL; +#ifdef HAVE_STRUCT_SIGINFO_T + psig->siginfo = *siginfo; +#endif + /* the head check is important, as the tick handler cannot atomically clear both * the head and tail */ if (PCNTL_G(head) && PCNTL_G(tail)) { @@ -1317,11 +1387,14 @@ static void pcntl_signal_handler(int signo) } PCNTL_G(tail) = psig; PCNTL_G(pending_signals) = 1; + if (PCNTL_G(async_signals)) { + EG(vm_interrupt) = 1; + } } void pcntl_signal_dispatch() { - zval param, *handle, retval; + zval params[2], *handle, retval; struct php_pcntl_pending_signal *queue, *next; sigset_t mask; sigset_t old_mask; @@ -1334,8 +1407,8 @@ void pcntl_signal_dispatch() sigfillset(&mask); sigprocmask(SIG_BLOCK, &mask, &old_mask); - /* Bail if the queue is empty or if we are already playing the queue*/ - if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) { + /* Bail if the queue is empty or if we are already playing the queue */ + if (!PCNTL_G(head) || PCNTL_G(processing_signal_queue)) { sigprocmask(SIG_SETMASK, &old_mask, NULL); return; } @@ -1347,17 +1420,25 @@ void pcntl_signal_dispatch() PCNTL_G(head) = NULL; /* simple stores are atomic */ /* Allocate */ - while (queue) { if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) { - ZVAL_NULL(&retval); - ZVAL_LONG(¶m, queue->signo); - - /* 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) */ - call_user_function(EG(function_table), NULL, handle, &retval, 1, ¶m); - zval_ptr_dtor(¶m); - zval_ptr_dtor(&retval); + if (Z_TYPE_P(handle) != IS_LONG) { + ZVAL_NULL(&retval); + ZVAL_LONG(¶ms[0], queue->signo); +#ifdef HAVE_STRUCT_SIGINFO_T + array_init(¶ms[1]); + pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, ¶ms[1]); +#else + ZVAL_NULL(¶ms[1]); +#endif + + /* 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) */ + call_user_function(EG(function_table), NULL, handle, &retval, 2, params); + zval_ptr_dtor(&retval); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + } } next = queue->next; @@ -1375,7 +1456,30 @@ void pcntl_signal_dispatch() sigprocmask(SIG_SETMASK, &old_mask, NULL); } +/* {{{ proto bool pcntl_async_signals([bool on[) + Enable/disable asynchronous signal handling and return the old setting. */ +PHP_FUNCTION(pcntl_async_signals) +{ + zend_bool on; + if (ZEND_NUM_ARGS() == 0) { + RETURN_BOOL(PCNTL_G(async_signals)); + } + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &on) == FAILURE) { + return; + } + RETVAL_BOOL(PCNTL_G(async_signals)); + PCNTL_G(async_signals) = on; +} +/* }}} */ + +static void pcntl_interrupt_function(zend_execute_data *execute_data) +{ + pcntl_signal_dispatch(); + if (orig_interrupt_function) { + orig_interrupt_function(execute_data); + } +} /* * Local variables: diff --git a/ext/pcntl/php_pcntl.h b/ext/pcntl/php_pcntl.h index a2c56db308..4b75afcfdd 100644 --- a/ext/pcntl/php_pcntl.h +++ b/ext/pcntl/php_pcntl.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2017 The PHP Group | + | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -51,15 +51,18 @@ PHP_FUNCTION(pcntl_wexitstatus); PHP_FUNCTION(pcntl_wtermsig); PHP_FUNCTION(pcntl_wstopsig); PHP_FUNCTION(pcntl_signal); +PHP_FUNCTION(pcntl_signal_get_handler); PHP_FUNCTION(pcntl_signal_dispatch); PHP_FUNCTION(pcntl_get_last_error); PHP_FUNCTION(pcntl_strerror); #ifdef HAVE_SIGPROCMASK PHP_FUNCTION(pcntl_sigprocmask); #endif -#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT +#ifdef HAVE_STRUCT_SIGINFO_T +# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT PHP_FUNCTION(pcntl_sigwaitinfo); PHP_FUNCTION(pcntl_sigtimedwait); +# endif #endif PHP_FUNCTION(pcntl_exec); #ifdef HAVE_GETPRIORITY @@ -68,10 +71,14 @@ PHP_FUNCTION(pcntl_getpriority); #ifdef HAVE_SETPRIORITY PHP_FUNCTION(pcntl_setpriority); #endif +PHP_FUNCTION(pcntl_async_signals); struct php_pcntl_pending_signal { struct php_pcntl_pending_signal *next; zend_long signo; +#ifdef HAVE_STRUCT_SIGINFO_T + siginfo_t siginfo; +#endif }; ZEND_BEGIN_MODULE_GLOBALS(pcntl) @@ -80,6 +87,7 @@ ZEND_BEGIN_MODULE_GLOBALS(pcntl) struct php_pcntl_pending_signal *head, *tail, *spares; int last_error; volatile char pending_signals; + zend_bool async_signals; ZEND_END_MODULE_GLOBALS(pcntl) #ifdef ZTS diff --git a/ext/pcntl/php_signal.c b/ext/pcntl/php_signal.c index 8f1b350016..7ef2cb4b38 100644 --- a/ext/pcntl/php_signal.c +++ b/ext/pcntl/php_signal.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2017 The PHP Group | + | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -28,15 +28,21 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all) { struct sigaction act,oact; -#ifdef ZEND_SIGNALS -#endif + +#ifdef HAVE_STRUCT_SIGINFO_T + act.sa_sigaction = func; +#else act.sa_handler = func; +#endif if (mask_all) { sigfillset(&act.sa_mask); } else { sigemptyset(&act.sa_mask); } act.sa_flags = 0; +#ifdef HAVE_STRUCT_SIGINFO_T + act.sa_flags |= SA_SIGINFO; +#endif if (signo == SIGALRM || (! restart)) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS */ @@ -46,16 +52,15 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all) act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ #endif } -#ifdef ZEND_SIGNALS - if (zend_sigaction(signo, &act, &oact) < 0) -#else - if (sigaction(signo, &act, &oact) < 0) -#endif - { - return SIG_ERR; + if (zend_sigaction(signo, &act, &oact) < 0) { + return (Sigfunc*)SIG_ERR; } +#ifdef HAVE_STRUCT_SIGINFO_T + return oact.sa_sigaction; +#else return oact.sa_handler; +#endif } Sigfunc *php_signal(int signo, Sigfunc *func, int restart) diff --git a/ext/pcntl/php_signal.h b/ext/pcntl/php_signal.h index b8c81d251c..bc6f6f1459 100644 --- a/ext/pcntl/php_signal.h +++ b/ext/pcntl/php_signal.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2017 The PHP Group | + | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -29,7 +29,11 @@ # define SIGRTMAX 64 #endif +#ifdef HAVE_STRUCT_SIGINFO_T +typedef void Sigfunc(int, siginfo_t*, void*); +#else typedef void Sigfunc(int); +#endif Sigfunc *php_signal(int signo, Sigfunc *func, int restart); Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all); diff --git a/ext/pcntl/tests/async_signals.phpt b/ext/pcntl/tests/async_signals.phpt new file mode 100644 index 0000000000..b650606df3 --- /dev/null +++ b/ext/pcntl/tests/async_signals.phpt @@ -0,0 +1,25 @@ +--TEST-- +Asynchronous signal handling through VM interrupts +--SKIPIF-- +<?php + if (!extension_loaded("pcntl")) print "skip"; + elseif (!function_exists("pcntl_signal")) print "skip pcntl_signal() not available"; + elseif (!function_exists("posix_kill")) print "skip posix_kill() not available"; + elseif (!function_exists("posix_getpid")) print "skip posix_getpid() not available"; +?> +--FILE-- +<?php +pcntl_async_signals(1); + +pcntl_signal(SIGTERM, function ($signo) { echo "Signal handler called!\n"; }); + +echo "Start!\n"; +posix_kill(posix_getpid(), SIGTERM); +$i = 0; // dummy +echo "Done!\n"; + +?> +--EXPECTF-- +Start! +Signal handler called! +Done! diff --git a/ext/pcntl/tests/bug73783.phpt b/ext/pcntl/tests/bug73783.phpt new file mode 100644 index 0000000000..beacdf6b8d --- /dev/null +++ b/ext/pcntl/tests/bug73783.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #73783: (SIG_IGN needs to be set to prevent syscals from returning early) +--SKIPIF-- +<?php + if (!extension_loaded('pcntl')) die('skip pcntl extension not available'); + elseif (!extension_loaded('posix')) die('skip posix extension not available'); +?> +--FILE-- +<?php +pcntl_signal(SIGCHLD, SIG_IGN); + +switch(pcntl_fork()) { + case 0: + exit; + break; +} + +$before = microtime(true); +sleep(1); + +if (microtime(true) - $before >= 0.8) { + echo "working\n"; +} else { + echo "failed\n"; +} +?> +--EXPECTF-- +working diff --git a/ext/pcntl/tests/pcntl_signal.phpt b/ext/pcntl/tests/pcntl_signal.phpt index 2db01305b5..a6441935c1 100644 --- a/ext/pcntl/tests/pcntl_signal.phpt +++ b/ext/pcntl/tests/pcntl_signal.phpt @@ -11,6 +11,12 @@ pcntl_signal(SIGTERM, function($signo){ posix_kill(posix_getpid(), SIGTERM); pcntl_signal_dispatch(); +pcntl_signal(SIGUSR1, function($signo, $siginfo){ + printf("got signal from %s\n", $siginfo['pid'] ?? 'nobody'); +}); +posix_kill(posix_getpid(), SIGUSR1); +pcntl_signal_dispatch(); + var_dump(pcntl_signal()); var_dump(pcntl_signal(SIGALRM, SIG_IGN)); var_dump(pcntl_signal(-1, -1)); @@ -24,6 +30,7 @@ echo "ok\n"; ?> --EXPECTF-- signal dispatched +got signal from %r\d+|nobody%r Warning: pcntl_signal() expects at least 2 parameters, 0 given in %s NULL diff --git a/ext/pcntl/tests/pcntl_signal_get_handler.phpt b/ext/pcntl/tests/pcntl_signal_get_handler.phpt new file mode 100644 index 0000000000..48f911e5e3 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_get_handler.phpt @@ -0,0 +1,30 @@ +--TEST-- +pcntl_signal_get_handler() +--SKIPIF-- +<?php if (!extension_loaded("pcntl")) print "skip"; ?> +<?php if (!extension_loaded("posix")) die("skip posix extension not available"); ?> +--FILE-- +<?php +var_dump(pcntl_signal_get_handler(SIGUSR1)); + +function pcntl_test($signo) {} +pcntl_signal(SIGUSR1, 'pcntl_test'); +var_dump(pcntl_signal_get_handler(SIGUSR1)); + +pcntl_signal(SIGUSR1, SIG_DFL); +var_dump(pcntl_signal_get_handler(SIGUSR1)); + +pcntl_signal(SIGUSR1, SIG_IGN); +var_dump(pcntl_signal_get_handler(SIGUSR1)); + +posix_kill(posix_getpid(), SIGUSR1); +pcntl_signal_dispatch(); + +echo "ok\n"; +?> +--EXPECTF-- +int(0) +string(10) "pcntl_test" +int(0) +int(1) +ok |