Skip to content

Commit f64388e

Browse files
committed
pnctl_signal(): add siginfo to handler args
Feature will utilize already available siginfo parsing and extend the handler for signals to provide an array of the siginfo_t data. RFC:https://wiki.php.net/rfc/additional-context-in-pcntl-signal-handler
1 parent ab30457 commit f64388e

File tree

6 files changed

+125
-42
lines changed

6 files changed

+125
-42
lines changed

ext/pcntl/config.m4

+17-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,21 @@ if test "$PHP_PCNTL" != "no"; then
1010
AC_CHECK_FUNCS(waitpid, [ AC_DEFINE(HAVE_WAITPID,1,[ ]) ], [ AC_MSG_ERROR(pcntl: waitpid() not supported by this platform) ])
1111
AC_CHECK_FUNCS(sigaction, [ AC_DEFINE(HAVE_SIGACTION,1,[ ]) ], [ AC_MSG_ERROR(pcntl: sigaction() not supported by this platform) ])
1212
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigprocmask sigwaitinfo sigtimedwait])
13-
PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli)
13+
14+
AC_MSG_CHECKING([for siginfo_t])
15+
AC_TRY_COMPILE([
16+
#include <signal.h>
17+
#ifdef HAVE_SIGINFO_H
18+
#include <siginfo.h>
19+
#endif
20+
],[
21+
siginfo_t info;
22+
],[
23+
AC_MSG_RESULT([yes])
24+
PCNTL_CFLAGS="-DHAVE_STRUCT_SIGINFO_T"
25+
], [
26+
AC_MSG_RESULT([no])
27+
])
28+
29+
PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli, $PCNTL_CFLAGS)
1430
fi

ext/pcntl/pcntl.c

+79-39
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
8282
ZEND_ARG_INFO(1, oldset)
8383
ZEND_END_ARG_INFO()
8484

85+
#ifdef HAVE_STRUCT_SIGINFO_T
86+
# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
8587
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
8688
ZEND_ARG_INFO(0, set)
8789
ZEND_ARG_INFO(1, info)
@@ -93,6 +95,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
9395
ZEND_ARG_INFO(0, seconds)
9496
ZEND_ARG_INFO(0, nanoseconds)
9597
ZEND_END_ARG_INFO()
98+
# endif
99+
#endif
96100

97101
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
98102
ZEND_ARG_INFO(0, status)
@@ -185,9 +189,11 @@ const zend_function_entry pcntl_functions[] = {
185189
#ifdef HAVE_SIGPROCMASK
186190
PHP_FE(pcntl_sigprocmask, arginfo_pcntl_sigprocmask)
187191
#endif
188-
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
192+
#ifdef HAVE_STRUCT_SIGINFO_T
193+
# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
189194
PHP_FE(pcntl_sigwaitinfo, arginfo_pcntl_sigwaitinfo)
190195
PHP_FE(pcntl_sigtimedwait, arginfo_pcntl_sigtimedwait)
196+
# endif
191197
#endif
192198
#ifdef HAVE_WCONTINUED
193199
PHP_FE(pcntl_wifcontinued, arginfo_pcntl_wifcontinued)
@@ -219,7 +225,12 @@ ZEND_GET_MODULE(pcntl)
219225

220226
static void (*orig_interrupt_function)(zend_execute_data *execute_data);
221227

228+
#ifdef HAVE_STRUCT_SIGINFO_T
229+
static void pcntl_signal_handler(int, siginfo_t*, void*);
230+
static void pcntl_siginfo_to_zval(int, siginfo_t*, zval*);
231+
#else
222232
static void pcntl_signal_handler(int);
233+
#endif
223234
static void pcntl_signal_dispatch();
224235
static void pcntl_interrupt_function(zend_execute_data *execute_data);
225236

@@ -997,7 +1008,7 @@ PHP_FUNCTION(pcntl_signal)
9971008
php_error_docref(NULL, E_WARNING, "Invalid value for handle argument specified");
9981009
RETURN_FALSE;
9991010
}
1000-
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
1011+
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == (Sigfunc *)SIG_ERR) {
10011012
PCNTL_G(last_error) = errno;
10021013
php_error_docref(NULL, E_WARNING, "Error assigning signal");
10031014
RETURN_FALSE;
@@ -1019,7 +1030,7 @@ PHP_FUNCTION(pcntl_signal)
10191030
if (Z_REFCOUNTED_P(handle)) Z_ADDREF_P(handle);
10201031
}
10211032

1022-
if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
1033+
if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == (Sigfunc *)SIG_ERR) {
10231034
PCNTL_G(last_error) = errno;
10241035
php_error_docref(NULL, E_WARNING, "Error assigning signal");
10251036
RETURN_FALSE;
@@ -1114,7 +1125,8 @@ PHP_FUNCTION(pcntl_sigprocmask)
11141125
/* }}} */
11151126
#endif
11161127

1117-
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
1128+
#ifdef HAVE_STRUCT_SIGINFO_T
1129+
# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
11181130
static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
11191131
{
11201132
zval *user_set, *user_signo, *user_siginfo = NULL;
@@ -1168,65 +1180,75 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
11681180
if (!signo && siginfo.si_signo) {
11691181
signo = siginfo.si_signo;
11701182
}
1183+
pcntl_siginfo_to_zval(signo, &siginfo, user_siginfo);
1184+
RETURN_LONG(signo);
1185+
}
1186+
/* }}} */
1187+
1188+
/* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1189+
Synchronously wait for queued signals */
1190+
PHP_FUNCTION(pcntl_sigwaitinfo)
1191+
{
1192+
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1193+
}
1194+
/* }}} */
1195+
1196+
/* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1197+
Wait for queued signals */
1198+
PHP_FUNCTION(pcntl_sigtimedwait)
1199+
{
1200+
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1201+
}
1202+
/* }}} */
1203+
# endif
11711204

1205+
static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */
1206+
{
11721207
if (signo > 0 && user_siginfo) {
11731208
if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
11741209
zval_dtor(user_siginfo);
11751210
array_init(user_siginfo);
11761211
} else {
11771212
zend_hash_clean(Z_ARRVAL_P(user_siginfo));
11781213
}
1179-
add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo.si_signo);
1180-
add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo.si_errno);
1181-
add_assoc_long_ex(user_siginfo, "code", sizeof("code")-1, siginfo.si_code);
1214+
add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo->si_signo);
1215+
add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo->si_errno);
1216+
add_assoc_long_ex(user_siginfo, "code", sizeof("code")-1, siginfo->si_code);
11821217
switch(signo) {
11831218
#ifdef SIGCHLD
11841219
case SIGCHLD:
1185-
add_assoc_long_ex(user_siginfo, "status", sizeof("status")-1, siginfo.si_status);
1220+
add_assoc_long_ex(user_siginfo, "status", sizeof("status")-1, siginfo->si_status);
11861221
# ifdef si_utime
1187-
add_assoc_double_ex(user_siginfo, "utime", sizeof("utime")-1, siginfo.si_utime);
1222+
add_assoc_double_ex(user_siginfo, "utime", sizeof("utime")-1, siginfo->si_utime);
11881223
# endif
11891224
# ifdef si_stime
1190-
add_assoc_double_ex(user_siginfo, "stime", sizeof("stime")-1, siginfo.si_stime);
1225+
add_assoc_double_ex(user_siginfo, "stime", sizeof("stime")-1, siginfo->si_stime);
11911226
# endif
1192-
add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo.si_pid);
1193-
add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo.si_uid);
1227+
add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
1228+
add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
1229+
break;
1230+
case SIGUSR1:
1231+
case SIGUSR2:
1232+
add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
1233+
add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
11941234
break;
11951235
#endif
11961236
case SIGILL:
11971237
case SIGFPE:
11981238
case SIGSEGV:
11991239
case SIGBUS:
1200-
add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo.si_addr);
1240+
add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
12011241
break;
12021242
#ifdef SIGPOLL
12031243
case SIGPOLL:
1204-
add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo.si_band);
1244+
add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo->si_band);
12051245
# ifdef si_fd
1206-
add_assoc_long_ex(user_siginfo, "fd", sizeof("fd")-1, siginfo.si_fd);
1246+
add_assoc_long_ex(user_siginfo, "fd", sizeof("fd")-1, siginfo->si_fd);
12071247
# endif
12081248
break;
12091249
#endif
12101250
}
12111251
}
1212-
1213-
RETURN_LONG(signo);
1214-
}
1215-
/* }}} */
1216-
1217-
/* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1218-
Synchronously wait for queued signals */
1219-
PHP_FUNCTION(pcntl_sigwaitinfo)
1220-
{
1221-
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1222-
}
1223-
/* }}} */
1224-
1225-
/* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1226-
Wait for queued signals */
1227-
PHP_FUNCTION(pcntl_sigtimedwait)
1228-
{
1229-
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
12301252
}
12311253
/* }}} */
12321254
#endif
@@ -1333,7 +1355,11 @@ PHP_FUNCTION(pcntl_strerror)
13331355
/* }}} */
13341356

13351357
/* Our custom signal handler that calls the appropriate php_function */
1358+
#ifdef HAVE_STRUCT_SIGINFO_T
1359+
static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context)
1360+
#else
13361361
static void pcntl_signal_handler(int signo)
1362+
#endif
13371363
{
13381364
struct php_pcntl_pending_signal *psig;
13391365

@@ -1347,6 +1373,14 @@ static void pcntl_signal_handler(int signo)
13471373
psig->signo = signo;
13481374
psig->next = NULL;
13491375

1376+
#ifdef HAVE_STRUCT_SIGINFO_T
1377+
zval user_siginfo;
1378+
ZVAL_NEW_ARR(&user_siginfo);
1379+
array_init(&user_siginfo);
1380+
pcntl_siginfo_to_zval(signo, siginfo, &user_siginfo);
1381+
psig->siginfo = Z_ARRVAL(user_siginfo);
1382+
#endif
1383+
13501384
/* the head check is important, as the tick handler cannot atomically clear both
13511385
* the head and tail */
13521386
if (PCNTL_G(head) && PCNTL_G(tail)) {
@@ -1363,7 +1397,7 @@ static void pcntl_signal_handler(int signo)
13631397

13641398
void pcntl_signal_dispatch()
13651399
{
1366-
zval param, *handle, retval;
1400+
zval params[2], *handle, retval;
13671401
struct php_pcntl_pending_signal *queue, *next;
13681402
sigset_t mask;
13691403
sigset_t old_mask;
@@ -1376,8 +1410,8 @@ void pcntl_signal_dispatch()
13761410
sigfillset(&mask);
13771411
sigprocmask(SIG_BLOCK, &mask, &old_mask);
13781412

1379-
/* Bail if the queue is empty or if we are already playing the queue*/
1380-
if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1413+
/* Bail if the queue is empty or if we are already playing the queue */
1414+
if (!PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
13811415
sigprocmask(SIG_SETMASK, &old_mask, NULL);
13821416
return;
13831417
}
@@ -1394,13 +1428,19 @@ void pcntl_signal_dispatch()
13941428
if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
13951429
if (Z_TYPE_P(handle) != IS_LONG) {
13961430
ZVAL_NULL(&retval);
1397-
ZVAL_LONG(&param, queue->signo);
1431+
ZVAL_LONG(&params[0], queue->signo);
1432+
#ifdef HAVE_STRUCT_SIGINFO_T
1433+
ZVAL_ARR(&params[1], queue->siginfo);
1434+
#else
1435+
ZVAL_NULL(&params[1]);
1436+
#endif
13981437

13991438
/* Call php signal handler - Note that we do not report errors, and we ignore the return value */
14001439
/* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1401-
call_user_function(EG(function_table), NULL, handle, &retval, 1, &param);
1402-
zval_ptr_dtor(&param);
1440+
call_user_function(EG(function_table), NULL, handle, &retval, 2, params);
14031441
zval_ptr_dtor(&retval);
1442+
zval_ptr_dtor(&params[0]);
1443+
zval_ptr_dtor(&params[1]);
14041444
}
14051445
}
14061446

ext/pcntl/php_pcntl.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ PHP_FUNCTION(pcntl_strerror);
5858
#ifdef HAVE_SIGPROCMASK
5959
PHP_FUNCTION(pcntl_sigprocmask);
6060
#endif
61-
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
61+
#ifdef HAVE_STRUCT_SIGINFO_T
62+
# if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
6263
PHP_FUNCTION(pcntl_sigwaitinfo);
6364
PHP_FUNCTION(pcntl_sigtimedwait);
65+
# endif
6466
#endif
6567
PHP_FUNCTION(pcntl_exec);
6668
#ifdef HAVE_GETPRIORITY
@@ -74,6 +76,9 @@ PHP_FUNCTION(pcntl_async_signals);
7476
struct php_pcntl_pending_signal {
7577
struct php_pcntl_pending_signal *next;
7678
zend_long signo;
79+
#ifdef HAVE_STRUCT_SIGINFO_T
80+
zend_array *siginfo;
81+
#endif
7782
};
7883

7984
ZEND_BEGIN_MODULE_GLOBALS(pcntl)

ext/pcntl/php_signal.c

+12-1
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
2929
{
3030
struct sigaction act,oact;
3131

32+
#ifdef HAVE_STRUCT_SIGINFO_T
33+
act.sa_sigaction = func;
34+
#else
3235
act.sa_handler = func;
36+
#endif
3337
if (mask_all) {
3438
sigfillset(&act.sa_mask);
3539
} else {
3640
sigemptyset(&act.sa_mask);
3741
}
3842
act.sa_flags = 0;
43+
#ifdef HAVE_STRUCT_SIGINFO_T
44+
act.sa_flags |= SA_SIGINFO;
45+
#endif
3946
if (signo == SIGALRM || (! restart)) {
4047
#ifdef SA_INTERRUPT
4148
act.sa_flags |= SA_INTERRUPT; /* SunOS */
@@ -46,10 +53,14 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
4653
#endif
4754
}
4855
if (zend_sigaction(signo, &act, &oact) < 0) {
49-
return SIG_ERR;
56+
return (Sigfunc*)SIG_ERR;
5057
}
5158

59+
#ifdef HAVE_STRUCT_SIGINFO_T
60+
return oact.sa_sigaction;
61+
#else
5262
return oact.sa_handler;
63+
#endif
5364
}
5465

5566
Sigfunc *php_signal(int signo, Sigfunc *func, int restart)

ext/pcntl/php_signal.h

+4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@
2929
# define SIGRTMAX 64
3030
#endif
3131

32+
#ifdef HAVE_STRUCT_SIGINFO_T
33+
typedef void Sigfunc(int, siginfo_t*, void*);
34+
#else
3235
typedef void Sigfunc(int);
36+
#endif
3337
Sigfunc *php_signal(int signo, Sigfunc *func, int restart);
3438
Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all);
3539

ext/pcntl/tests/pcntl_signal.phpt

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ pcntl_signal(SIGTERM, function($signo){
1111
posix_kill(posix_getpid(), SIGTERM);
1212
pcntl_signal_dispatch();
1313

14+
pcntl_signal(SIGUSR1, function($signo, $siginfo){
15+
printf("got signal from %s\n", $siginfo['pid'] ?? 'nobody');
16+
});
17+
posix_kill(posix_getpid(), SIGUSR1);
18+
pcntl_signal_dispatch();
19+
1420
var_dump(pcntl_signal());
1521
var_dump(pcntl_signal(SIGALRM, SIG_IGN));
1622
var_dump(pcntl_signal(-1, -1));
@@ -24,6 +30,7 @@ echo "ok\n";
2430
?>
2531
--EXPECTF--
2632
signal dispatched
33+
got signal from %r\d+|nobody%r
2734

2835
Warning: pcntl_signal() expects at least 2 parameters, 0 given in %s
2936
NULL

0 commit comments

Comments
 (0)