Skip to content

Commit c58e2b9

Browse files
committed
MFH: Added pcntl_sigwaitinfo(), pcntl_sigtimedwait() and pcntl_sigprocmask()
[DOC] pcntl_sigprocmask() allows to block signals. pcntl_sigwaitinfo() allows to fetch blocked signals or signals delivered while pcntl_sigwaitinfo() is running. pcntl_sigtimedwait() is pcntl_sigwaitinfo() with a timeout.
1 parent 204fcbe commit c58e2b9

File tree

5 files changed

+358
-1
lines changed

5 files changed

+358
-1
lines changed

NEWS

+6
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ PHP NEWS
210210
DateInterval on each iteration, up to an end date or limited by maximum
211211
number of occurences.
212212

213+
- Improved pcntl extension: (Arnaud)
214+
. Added pcntl_signal_dispatch()
215+
. Added pcntl_sigprocmask()
216+
. Added pcntl_sigwaitinfo()
217+
. Added pcntl_sigtimedwait()
218+
213219
- Added hash_copy() function. (Tony)
214220
- Added sha224 hash algorithm to the hash extension. (Scott)
215221
- Added ReflectionProperty::setAccessible() method that allows non-public

ext/pcntl/config.m4

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ if test "$PHP_PCNTL" != "no"; then
1313
AC_CHECK_FUNCS(fork, [ AC_DEFINE(HAVE_FORK,1,[ ]) ], [ AC_MSG_ERROR(pcntl: fork() not supported by this platform) ])
1414
AC_CHECK_FUNCS(waitpid, [ AC_DEFINE(HAVE_WAITPID,1,[ ]) ], [ AC_MSG_ERROR(pcntl: fork() not supported by this platform) ])
1515
AC_CHECK_FUNCS(sigaction, [ AC_DEFINE(HAVE_SIGACTION,1,[ ]) ], [ AC_MSG_ERROR(pcntl: sigaction() not supported by this platform) ])
16-
AC_CHECK_FUNCS(getpriority setpriority wait3)
16+
AC_CHECK_FUNCS(getpriority setpriority wait3 sigprocmask sigwaitinfo sigtimedwait)
1717

1818
PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli)
1919
fi

ext/pcntl/pcntl.c

+257
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
6969
ZEND_ARG_INFO(0, restart_syscalls)
7070
ZEND_END_ARG_INFO()
7171

72+
static
73+
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
74+
ZEND_ARG_INFO(0, how)
75+
ZEND_ARG_INFO(0, set)
76+
ZEND_END_ARG_INFO()
77+
78+
static
79+
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
80+
ZEND_ARG_INFO(0, set)
81+
ZEND_ARG_INFO(1, info)
82+
ZEND_END_ARG_INFO()
83+
84+
static
85+
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
86+
ZEND_ARG_INFO(0, set)
87+
ZEND_ARG_INFO(1, info)
88+
ZEND_ARG_INFO(0, seconds)
89+
ZEND_ARG_INFO(0, nanoseconds)
90+
ZEND_END_ARG_INFO()
91+
7292
static
7393
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
7494
ZEND_ARG_INFO(0, status)
@@ -148,6 +168,13 @@ const zend_function_entry pcntl_functions[] = {
148168
#endif
149169
#ifdef HAVE_SETPRIORITY
150170
PHP_FE(pcntl_setpriority, arginfo_pcntl_setpriority)
171+
#endif
172+
#ifdef HAVE_SIGPROCMASK
173+
PHP_FE(pcntl_sigprocmask, arginfo_pcntl_sigprocmask)
174+
#endif
175+
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
176+
PHP_FE(pcntl_sigwaitinfo, arginfo_pcntl_sigwaitinfo)
177+
PHP_FE(pcntl_sigtimedwait, arginfo_pcntl_sigtimedwait)
151178
#endif
152179
{NULL, NULL, NULL}
153180
};
@@ -246,6 +273,81 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
246273
REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
247274
REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
248275
#endif
276+
277+
/* {{{ "how" argument for sigprocmask */
278+
#ifdef HAVE_SIGPROCMASK
279+
REGISTER_LONG_CONSTANT("SIG_BLOCK", SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
280+
REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
281+
REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
282+
#endif
283+
/* }}} */
284+
285+
/* {{{ si_code */
286+
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
287+
REGISTER_LONG_CONSTANT("SI_USER", SI_USER, CONST_CS | CONST_PERSISTENT);
288+
#ifdef SI_NOINFO
289+
REGISTER_LONG_CONSTANT("SI_NOINFO", SI_NOINFO, CONST_CS | CONST_PERSISTENT);
290+
#endif
291+
#ifdef SI_KERNEL
292+
REGISTER_LONG_CONSTANT("SI_KERNEL", SI_KERNEL, CONST_CS | CONST_PERSISTENT);
293+
#endif
294+
REGISTER_LONG_CONSTANT("SI_QUEUE", SI_QUEUE, CONST_CS | CONST_PERSISTENT);
295+
REGISTER_LONG_CONSTANT("SI_TIMER", SI_TIMER, CONST_CS | CONST_PERSISTENT);
296+
REGISTER_LONG_CONSTANT("SI_MESGQ", SI_MESGQ, CONST_CS | CONST_PERSISTENT);
297+
REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
298+
#ifdef SI_SIGIO
299+
REGISTER_LONG_CONSTANT("SI_SIGIO", SI_SIGIO, CONST_CS | CONST_PERSISTENT);
300+
#endif
301+
#ifdef SI_TKILL
302+
REGISTER_LONG_CONSTANT("SI_TKILL", SI_TKILL, CONST_CS | CONST_PERSISTENT);
303+
#endif
304+
305+
/* si_code for SIGCHILD */
306+
REGISTER_LONG_CONSTANT("CLD_EXITED", CLD_EXITED, CONST_CS | CONST_PERSISTENT);
307+
REGISTER_LONG_CONSTANT("CLD_KILLED", CLD_KILLED, CONST_CS | CONST_PERSISTENT);
308+
REGISTER_LONG_CONSTANT("CLD_DUMPED", CLD_DUMPED, CONST_CS | CONST_PERSISTENT);
309+
REGISTER_LONG_CONSTANT("CLD_TRAPPED", CLD_TRAPPED, CONST_CS | CONST_PERSISTENT);
310+
REGISTER_LONG_CONSTANT("CLD_STOPPED", CLD_STOPPED, CONST_CS | CONST_PERSISTENT);
311+
REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
312+
313+
/* si_code for SIGTRAP */
314+
REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
315+
REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
316+
317+
/* si_code for SIGPOLL */
318+
REGISTER_LONG_CONSTANT("POLL_IN", POLL_IN, CONST_CS | CONST_PERSISTENT);
319+
REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
320+
REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
321+
REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
322+
REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
323+
REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
324+
325+
REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
326+
REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
327+
REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
328+
REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
329+
REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
330+
REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
331+
REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
332+
REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
333+
334+
REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
335+
REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
336+
REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
337+
REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
338+
REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
339+
REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
340+
REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
341+
REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
342+
343+
REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
344+
REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
345+
346+
REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
347+
REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
348+
REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
349+
#endif
350+
/* }}} */
249351
}
250352

251353
static PHP_GINIT_FUNCTION(pcntl)
@@ -654,6 +756,161 @@ PHP_FUNCTION(pcntl_signal_dispatch)
654756
}
655757
/* }}} */
656758

759+
#ifdef HAVE_SIGPROCMASK
760+
/* {{{ proto bool pcntl_sigprocmask(int how, array set)
761+
Examine and change blocked signals */
762+
PHP_FUNCTION(pcntl_sigprocmask)
763+
{
764+
long how, signo;
765+
zval *user_set, **user_signo;
766+
sigset_t set;
767+
HashPosition pos;
768+
769+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la", &how, &user_set) == FAILURE) {
770+
return;
771+
}
772+
773+
if (sigemptyset(&set) != 0) {
774+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
775+
RETURN_FALSE;
776+
}
777+
778+
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
779+
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
780+
{
781+
if (Z_TYPE_PP(user_signo) != IS_LONG) {
782+
SEPARATE_ZVAL(user_signo);
783+
convert_to_long_ex(user_signo);
784+
}
785+
signo = Z_LVAL_PP(user_signo);
786+
if (sigaddset(&set, signo) != 0) {
787+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
788+
RETURN_FALSE;
789+
}
790+
zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
791+
}
792+
793+
if (sigprocmask(how, &set, NULL) != 0) {
794+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
795+
RETURN_FALSE;
796+
}
797+
798+
RETURN_TRUE;
799+
}
800+
/* }}} */
801+
#endif
802+
803+
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
804+
static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
805+
{
806+
zval *user_set, **user_signo, *user_siginfo = NULL;
807+
long tv_sec = 0, tv_nsec = 0;
808+
sigset_t set;
809+
HashPosition pos;
810+
int signo;
811+
siginfo_t siginfo;
812+
struct timespec timeout;
813+
814+
if (timedwait) {
815+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
816+
return;
817+
}
818+
} else {
819+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) {
820+
return;
821+
}
822+
}
823+
824+
if (sigemptyset(&set) != 0) {
825+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
826+
RETURN_FALSE;
827+
}
828+
829+
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
830+
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
831+
{
832+
if (Z_TYPE_PP(user_signo) != IS_LONG) {
833+
SEPARATE_ZVAL(user_signo);
834+
convert_to_long_ex(user_signo);
835+
}
836+
signo = Z_LVAL_PP(user_signo);
837+
if (sigaddset(&set, signo) != 0) {
838+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
839+
RETURN_FALSE;
840+
}
841+
zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
842+
}
843+
844+
if (timedwait) {
845+
timeout.tv_sec = (time_t) tv_sec;
846+
timeout.tv_nsec = tv_nsec;
847+
signo = sigtimedwait(&set, &siginfo, &timeout);
848+
} else {
849+
signo = sigwaitinfo(&set, &siginfo);
850+
}
851+
if (signo == -1 && errno != EAGAIN) {
852+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
853+
}
854+
855+
if (signo > 0 && user_siginfo) {
856+
if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
857+
zval_dtor(user_siginfo);
858+
array_init(user_siginfo);
859+
}
860+
add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo);
861+
add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno);
862+
add_assoc_long_ex(user_siginfo, "code", sizeof("code"), siginfo.si_code);
863+
switch(signo) {
864+
#ifdef SIGCHLD
865+
case SIGCHLD:
866+
add_assoc_long_ex(user_siginfo, "status", sizeof("status"), siginfo.si_status);
867+
#ifdef si_utime
868+
add_assoc_double_ex(user_siginfo, "utime", sizeof("utime"), siginfo.si_utime);
869+
#endif
870+
#ifdef si_stime
871+
add_assoc_double_ex(user_siginfo, "stime", sizeof("stime"), siginfo.si_stime);
872+
#endif
873+
add_assoc_long_ex(user_siginfo, "pid", sizeof("pid"), siginfo.si_pid);
874+
add_assoc_long_ex(user_siginfo, "uid", sizeof("uid"), siginfo.si_uid);
875+
break;
876+
#endif
877+
case SIGILL:
878+
case SIGFPE:
879+
case SIGSEGV:
880+
case SIGBUS:
881+
add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr);
882+
break;
883+
#ifdef SIGPOLL
884+
case SIGPOLL:
885+
add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band);
886+
add_assoc_long_ex(user_siginfo, "fd", sizeof("fd"), siginfo.si_fd);
887+
break;
888+
#endif
889+
EMPTY_SWITCH_DEFAULT_CASE();
890+
}
891+
}
892+
893+
RETURN_LONG(signo);
894+
}
895+
/* }}} */
896+
897+
/* {{{ proto int sigwaitinfo(array set[, array &siginfo])
898+
Synchronously wait for queued signals */
899+
PHP_FUNCTION(pcntl_sigwaitinfo)
900+
{
901+
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
902+
}
903+
/* }}} */
904+
905+
/* {{{ proto int sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
906+
Wait for queued signals */
907+
PHP_FUNCTION(pcntl_sigtimedwait)
908+
{
909+
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
910+
}
911+
/* }}} */
912+
#endif
913+
657914
#ifdef HAVE_GETPRIORITY
658915
/* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
659916
Get the priority of any process */

ext/pcntl/php_pcntl.h

+7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ PHP_FUNCTION(pcntl_wtermsig);
4545
PHP_FUNCTION(pcntl_wstopsig);
4646
PHP_FUNCTION(pcntl_signal);
4747
PHP_FUNCTION(pcntl_signal_dispatch);
48+
#ifdef HAVE_SIGPROCMASK
49+
PHP_FUNCTION(pcntl_sigprocmask);
50+
#endif
51+
#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
52+
PHP_FUNCTION(pcntl_sigwaitinfo);
53+
PHP_FUNCTION(pcntl_sigtimedwait);
54+
#endif
4855
PHP_FUNCTION(pcntl_exec);
4956
#ifdef HAVE_GETPRIORITY
5057
PHP_FUNCTION(pcntl_getpriority);

0 commit comments

Comments
 (0)