Browse Source

Merge RFC Additional Context in pcntl_signal Handler

PHP-7.1.0beta1
Davey Shafik 10 years ago
parent
commit
57092c5a68
  1. 18
      ext/pcntl/config.m4
  2. 123
      ext/pcntl/pcntl.c
  3. 7
      ext/pcntl/php_pcntl.h
  4. 13
      ext/pcntl/php_signal.c
  5. 4
      ext/pcntl/php_signal.h
  6. 7
      ext/pcntl/tests/pcntl_signal.phpt

18
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

123
ext/pcntl/pcntl.c

@ -82,6 +82,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
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)
@ -93,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)
@ -185,9 +189,11 @@ 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)
@ -219,7 +225,12 @@ ZEND_GET_MODULE(pcntl)
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);
@ -549,6 +560,11 @@ PHP_RSHUTDOWN_FUNCTION(pcntl)
while (PCNTL_G(head)) {
sig = PCNTL_G(head);
PCNTL_G(head) = sig->next;
#ifdef HAVE_STRUCT_SIGINFO_T
if (sig->siginfo) {
zend_array_destroy(sig->siginfo);
}
#endif
efree(sig);
}
while (PCNTL_G(spares)) {
@ -997,7 +1013,7 @@ 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;
@ -1019,7 +1035,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;
@ -1114,7 +1130,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;
@ -1168,7 +1185,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);
@ -1176,57 +1216,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
@ -1333,7 +1360,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;
@ -1347,6 +1378,14 @@ static void pcntl_signal_handler(int signo)
psig->signo = signo;
psig->next = NULL;
#ifdef HAVE_STRUCT_SIGINFO_T
zval user_siginfo;
array_init(&user_siginfo);
pcntl_siginfo_to_zval(signo, siginfo, &user_siginfo);
psig->siginfo = zend_array_dup(Z_ARRVAL(user_siginfo));
zval_ptr_dtor(&user_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)) {
@ -1363,7 +1402,7 @@ static void pcntl_signal_handler(int signo)
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;
@ -1376,8 +1415,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;
}
@ -1394,13 +1433,19 @@ void pcntl_signal_dispatch()
if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
if (Z_TYPE_P(handle) != IS_LONG) {
ZVAL_NULL(&retval);
ZVAL_LONG(&param, queue->signo);
ZVAL_LONG(&params[0], queue->signo);
#ifdef HAVE_STRUCT_SIGINFO_T
ZVAL_ARR(&params[1], queue->siginfo);
#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, 1, &param);
zval_ptr_dtor(&param);
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]);
}
}

7
ext/pcntl/php_pcntl.h

@ -58,9 +58,11 @@ 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
@ -74,6 +76,9 @@ PHP_FUNCTION(pcntl_async_signals);
struct php_pcntl_pending_signal {
struct php_pcntl_pending_signal *next;
zend_long signo;
#ifdef HAVE_STRUCT_SIGINFO_T
zend_array *siginfo;
#endif
};
ZEND_BEGIN_MODULE_GLOBALS(pcntl)

13
ext/pcntl/php_signal.c

@ -29,13 +29,20 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
{
struct sigaction act,oact;
#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,10 +53,14 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
#endif
}
if (zend_sigaction(signo, &act, &oact) < 0) {
return SIG_ERR;
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)

4
ext/pcntl/php_signal.h

@ -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);

7
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

Loading…
Cancel
Save