summaryrefslogtreecommitdiff
path: root/ext/pcntl
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pcntl')
-rw-r--r--ext/pcntl/config.m418
-rw-r--r--ext/pcntl/pcntl.c212
-rw-r--r--ext/pcntl/php_pcntl.h12
-rw-r--r--ext/pcntl/php_signal.c25
-rw-r--r--ext/pcntl/php_signal.h6
-rw-r--r--ext/pcntl/tests/async_signals.phpt25
-rw-r--r--ext/pcntl/tests/bug73783.phpt28
-rw-r--r--ext/pcntl/tests/pcntl_signal.phpt7
-rw-r--r--ext/pcntl/tests/pcntl_signal_get_handler.phpt30
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(&param, 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, &param);
- zval_ptr_dtor(&param);
- zval_ptr_dtor(&retval);
+ if (Z_TYPE_P(handle) != IS_LONG) {
+ ZVAL_NULL(&retval);
+ ZVAL_LONG(&params[0], queue->signo);
+#ifdef HAVE_STRUCT_SIGINFO_T
+ array_init(&params[1]);
+ pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, &params[1]);
+#else
+ ZVAL_NULL(&params[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(&params[0]);
+ zval_ptr_dtor(&params[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