diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/pcntl | |
download | php2-c4dd7a1a684490673e25aaf4fabec5df138854c4.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/pcntl')
-rw-r--r-- | ext/pcntl/CREDITS | 2 | ||||
-rw-r--r-- | ext/pcntl/README | 16 | ||||
-rw-r--r-- | ext/pcntl/config.m4 | 14 | ||||
-rw-r--r-- | ext/pcntl/package.xml | 46 | ||||
-rw-r--r-- | ext/pcntl/pcntl.c | 1290 | ||||
-rw-r--r-- | ext/pcntl/php_pcntl.h | 91 | ||||
-rw-r--r-- | ext/pcntl/php_signal.c | 75 | ||||
-rw-r--r-- | ext/pcntl/php_signal.h | 36 | ||||
-rwxr-xr-x | ext/pcntl/test-pcntl.php | 40 | ||||
-rw-r--r-- | ext/pcntl/tests/001.phpt | 82 | ||||
-rw-r--r-- | ext/pcntl/tests/002.phpt | 103 | ||||
-rw-r--r-- | ext/pcntl/tests/003.phpt | 32 | ||||
-rw-r--r-- | ext/pcntl/tests/bug47566.phpt | 19 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_alarm.phpt | 23 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_exec.phpt | 15 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_exec_2.phpt | 27 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_exec_3.phpt | 17 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_fork_basic.phpt | 27 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_fork_variation.phpt | 48 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_get_last_error.phpt | 17 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_signal.phpt | 40 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_signal_dispatch.phpt | 26 | ||||
-rw-r--r-- | ext/pcntl/tests/pcntl_wait.phpt | 66 | ||||
-rw-r--r-- | ext/pcntl/tests/signal_closure_handler.phpt | 25 |
24 files changed, 2177 insertions, 0 deletions
diff --git a/ext/pcntl/CREDITS b/ext/pcntl/CREDITS new file mode 100644 index 0000000..cdf51d6 --- /dev/null +++ b/ext/pcntl/CREDITS @@ -0,0 +1,2 @@ +pcntl +Jason Greene, Arnaud Le Blanc diff --git a/ext/pcntl/README b/ext/pcntl/README new file mode 100644 index 0000000..cadd111 --- /dev/null +++ b/ext/pcntl/README @@ -0,0 +1,16 @@ +Process Control Module for PHP (pcntl) + +This module will attempt to implement all features related to process spawning and +control (fork(), waitpid(), signal(), WIF's, etc). This is extremly experimental, +with hope to become stable on most UNIX's. I greatly apreciate any feedback, fixes, +and or suggestions on how to improve/better implement +this functionality. + +Thanks, + +Jason Greeme < jason@inetgurus.net / jason@php.net > + + + + + diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 new file mode 100644 index 0000000..2ef07f1 --- /dev/null +++ b/ext/pcntl/config.m4 @@ -0,0 +1,14 @@ +dnl +dnl $Id$ +dnl + +PHP_ARG_ENABLE(pcntl, whether to enable pcntl support, +[ --enable-pcntl Enable pcntl support (CLI/CGI only)]) + +if test "$PHP_PCNTL" != "no"; then + AC_CHECK_FUNCS(fork, [ AC_DEFINE(HAVE_FORK,1,[ ]) ], [ AC_MSG_ERROR(pcntl: fork() not supported by this platform) ]) + 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 sigprocmask sigwaitinfo sigtimedwait]) + PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli) +fi diff --git a/ext/pcntl/package.xml b/ext/pcntl/package.xml new file mode 100644 index 0000000..b912739 --- /dev/null +++ b/ext/pcntl/package.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE package SYSTEM "../pear/package.dtd"> +<package> + <name>posix</name> + <summary>POSIX functions</summary> + <maintainers> + <maintainer> + <user>???</user> + <name>Kristian Köhntopp</name> + <email>kris@koehntopp.de</email> + <role>lead</role> + </maintainer> + </maintainers> + <description> +This module contains an interface to those functions defined +in the IEEE 1003.1 (POSIX.1) standards document which are not +accessible through other means. POSIX.1 for example defined the +open(), read(), write() and close() functions, too, which +traditionally have been part of PHP for a long time. Some more +system specific functions have not been available before, though, +and this module tries to remedy this by providing easy access +to these functions. + </description> + <license>PHP</license> + <release> + <state>beta</state> + <version>5.0.0rc1</version> + <date>2004-03-19</date> + <notes> +package.xml added to support installation using pear installer + </notes> + <filelist> + <file role="doc" name="CREDITS"/> + <file role="src" name="config.m4"/> + <file role="src" name="posix.c"/> + <file role="src" name="php_posix.h"/> + </filelist> + <deps> + <dep type="php" rel="ge" version="5" /> + <!-- doesn't work yet <dep type="os" rel="has" name="unix"/> --> + </deps> + </release> +</package> +<!-- +vim:et:ts=1:sw=1 +--> diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c new file mode 100644 index 0000000..47d58f5 --- /dev/null +++ b/ext/pcntl/pcntl.c @@ -0,0 +1,1290 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jason Greene <jason@inetgurus.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#define PCNTL_DEBUG 0 + +#if PCNTL_DEBUG +#define DEBUG_OUT printf("DEBUG: ");printf +#define IF_DEBUG(z) z +#else +#define IF_DEBUG(z) +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_pcntl.h" +#include "php_signal.h" +#include "php_ticks.h" + +#if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3 +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> +#endif + +#include <errno.h> + +ZEND_DECLARE_MODULE_GLOBALS(pcntl) +static PHP_GINIT_FUNCTION(pcntl); + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2) + ZEND_ARG_INFO(0, pid) + ZEND_ARG_INFO(1, status) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1) + ZEND_ARG_INFO(1, status) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2) + ZEND_ARG_INFO(0, signo) + ZEND_ARG_INFO(0, handler) + ZEND_ARG_INFO(0, restart_syscalls) +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() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1) + ZEND_ARG_INFO(0, set) + ZEND_ARG_INFO(1, info) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1) + ZEND_ARG_INFO(0, set) + ZEND_ARG_INFO(1, info) + ZEND_ARG_INFO(0, seconds) + ZEND_ARG_INFO(0, nanoseconds) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1) + ZEND_ARG_INFO(0, status) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1) + ZEND_ARG_INFO(0, path) + ZEND_ARG_INFO(0, args) + ZEND_ARG_INFO(0, envs) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1) + ZEND_ARG_INFO(0, seconds) +ZEND_END_ARG_INFO() + +#ifdef HAVE_GETPRIORITY +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0) + ZEND_ARG_INFO(0, pid) + ZEND_ARG_INFO(0, process_identifier) +ZEND_END_ARG_INFO() +#endif + +#ifdef HAVE_SETPRIORITY +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1) + ZEND_ARG_INFO(0, priority) + ZEND_ARG_INFO(0, pid) + ZEND_ARG_INFO(0, process_identifier) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1) + ZEND_ARG_INFO(0, errno) +ZEND_END_ARG_INFO() +/* }}} */ + +const zend_function_entry pcntl_functions[] = { + PHP_FE(pcntl_fork, arginfo_pcntl_void) + 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_dispatch, arginfo_pcntl_void) + PHP_FE(pcntl_wifexited, arginfo_pcntl_wifexited) + PHP_FE(pcntl_wifstopped, arginfo_pcntl_wifstopped) + PHP_FE(pcntl_wifsignaled, arginfo_pcntl_wifsignaled) + PHP_FE(pcntl_wexitstatus, arginfo_pcntl_wifexitstatus) + PHP_FE(pcntl_wtermsig, arginfo_pcntl_wtermsig) + PHP_FE(pcntl_wstopsig, arginfo_pcntl_wstopsig) + PHP_FE(pcntl_exec, arginfo_pcntl_exec) + PHP_FE(pcntl_alarm, arginfo_pcntl_alarm) + PHP_FE(pcntl_get_last_error, arginfo_pcntl_void) + PHP_FALIAS(pcntl_errno, pcntl_get_last_error, NULL) + PHP_FE(pcntl_strerror, arginfo_pcntl_strerror) +#ifdef HAVE_GETPRIORITY + PHP_FE(pcntl_getpriority, arginfo_pcntl_getpriority) +#endif +#ifdef HAVE_SETPRIORITY + PHP_FE(pcntl_setpriority, arginfo_pcntl_setpriority) +#endif +#ifdef HAVE_SIGPROCMASK + PHP_FE(pcntl_sigprocmask, arginfo_pcntl_sigprocmask) +#endif +#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT + PHP_FE(pcntl_sigwaitinfo, arginfo_pcntl_sigwaitinfo) + PHP_FE(pcntl_sigtimedwait, arginfo_pcntl_sigtimedwait) +#endif + PHP_FE_END +}; + +zend_module_entry pcntl_module_entry = { + STANDARD_MODULE_HEADER, + "pcntl", + pcntl_functions, + PHP_MINIT(pcntl), + PHP_MSHUTDOWN(pcntl), + PHP_RINIT(pcntl), + PHP_RSHUTDOWN(pcntl), + PHP_MINFO(pcntl), + NO_VERSION_YET, + PHP_MODULE_GLOBALS(pcntl), + PHP_GINIT(pcntl), + NULL, + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_PCNTL +ZEND_GET_MODULE(pcntl) +#endif + +static void pcntl_signal_handler(int); +static void pcntl_signal_dispatch(); + +void php_register_signal_constants(INIT_FUNC_ARGS) +{ + + /* Wait Constants */ +#ifdef WNOHANG + REGISTER_LONG_CONSTANT("WNOHANG", (long) WNOHANG, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef WUNTRACED + REGISTER_LONG_CONSTANT("WUNTRACED", (long) WUNTRACED, CONST_CS | CONST_PERSISTENT); +#endif + + /* Signal Constants */ + REGISTER_LONG_CONSTANT("SIG_IGN", (long) SIG_IGN, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_DFL", (long) SIG_DFL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_ERR", (long) SIG_ERR, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGHUP", (long) SIGHUP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGINT", (long) SIGINT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGQUIT", (long) SIGQUIT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGILL", (long) SIGILL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTRAP", (long) SIGTRAP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGABRT", (long) SIGABRT, CONST_CS | CONST_PERSISTENT); +#ifdef SIGIOT + REGISTER_LONG_CONSTANT("SIGIOT", (long) SIGIOT, CONST_CS | CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIGBUS", (long) SIGBUS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGFPE", (long) SIGFPE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGKILL", (long) SIGKILL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGUSR1", (long) SIGUSR1, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSEGV", (long) SIGSEGV, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGUSR2", (long) SIGUSR2, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPIPE", (long) SIGPIPE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGALRM", (long) SIGALRM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTERM", (long) SIGTERM, CONST_CS | CONST_PERSISTENT); +#ifdef SIGSTKFLT + REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SIGCLD + REGISTER_LONG_CONSTANT("SIGCLD", (long) SIGCLD, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SIGCHLD + REGISTER_LONG_CONSTANT("SIGCHLD", (long) SIGCHLD, CONST_CS | CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIGCONT", (long) SIGCONT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGSTOP", (long) SIGSTOP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTSTP", (long) SIGTSTP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTTIN", (long) SIGTTIN, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGTTOU", (long) SIGTTOU, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGURG", (long) SIGURG , CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGXCPU", (long) SIGXCPU, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGXFSZ", (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGPROF", (long) SIGPROF, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT); +#ifdef SIGPOLL + REGISTER_LONG_CONSTANT("SIGPOLL", (long) SIGPOLL, CONST_CS | CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SIGIO", (long) SIGIO, CONST_CS | CONST_PERSISTENT); +#ifdef SIGPWR + REGISTER_LONG_CONSTANT("SIGPWR", (long) SIGPWR, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SIGSYS + REGISTER_LONG_CONSTANT("SIGSYS", (long) SIGSYS, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIGBABY", (long) SIGSYS, CONST_CS | CONST_PERSISTENT); +#endif + +#if HAVE_GETPRIORITY || HAVE_SETPRIORITY + REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT); +#endif + + /* {{{ "how" argument for sigprocmask */ +#ifdef HAVE_SIGPROCMASK + REGISTER_LONG_CONSTANT("SIG_BLOCK", SIG_BLOCK, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT); +#endif + /* }}} */ + + /* {{{ si_code */ +#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT + REGISTER_LONG_CONSTANT("SI_USER", SI_USER, CONST_CS | CONST_PERSISTENT); +#ifdef SI_NOINFO + REGISTER_LONG_CONSTANT("SI_NOINFO", SI_NOINFO, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SI_KERNEL + REGISTER_LONG_CONSTANT("SI_KERNEL", SI_KERNEL, CONST_CS | CONST_PERSISTENT); +#endif + REGISTER_LONG_CONSTANT("SI_QUEUE", SI_QUEUE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SI_TIMER", SI_TIMER, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SI_MESGQ", SI_MESGQ, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT); +#ifdef SI_SIGIO + REGISTER_LONG_CONSTANT("SI_SIGIO", SI_SIGIO, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SI_TKILL + REGISTER_LONG_CONSTANT("SI_TKILL", SI_TKILL, CONST_CS | CONST_PERSISTENT); +#endif + + /* si_code for SIGCHILD */ +#ifdef CLD_EXITED + REGISTER_LONG_CONSTANT("CLD_EXITED", CLD_EXITED, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLD_KILLED + REGISTER_LONG_CONSTANT("CLD_KILLED", CLD_KILLED, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLD_DUMPED + REGISTER_LONG_CONSTANT("CLD_DUMPED", CLD_DUMPED, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLD_TRAPPED + REGISTER_LONG_CONSTANT("CLD_TRAPPED", CLD_TRAPPED, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLD_STOPPED + REGISTER_LONG_CONSTANT("CLD_STOPPED", CLD_STOPPED, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLD_CONTINUED + REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT); +#endif + + /* si_code for SIGTRAP */ +#ifdef TRAP_BRKPT + REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef TRAP_TRACE + REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT); +#endif + + /* si_code for SIGPOLL */ +#ifdef POLL_IN + REGISTER_LONG_CONSTANT("POLL_IN", POLL_IN, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef POLL_OUT + REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef POLL_MSG + REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef POLL_ERR + REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef POLL_PRI + REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef POLL_HUP + REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT); +#endif + +#ifdef ILL_ILLOPC + REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_ILLOPN + REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_ILLADR + REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_ILLTRP + REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_PRVOPC + REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_PRVREG + REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_COPROC + REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef ILL_BADSTK + REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT); +#endif + +#ifdef FPE_INTDIV + REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_INTOVF + REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTDIV + REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTOVF + REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTUND + REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTRES + REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTINV + REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef FPE_FLTSUB + REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT); +#endif + +#ifdef SEGV_MAPERR + REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef SEGV_ACCERR + REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT); +#endif + +#ifdef BUS_ADRALN + REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef BUS_ADRERR + REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef BUS_OBJERR + REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT); +#endif +#endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */ + /* }}} */ +} + +static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS) +{ +#ifdef EINTR + REGISTER_PCNTL_ERRNO_CONSTANT(EINTR); +#endif +#ifdef ECHILD + REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD); +#endif +#ifdef EINVAL + REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL); +#endif +#ifdef EAGAIN + REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN); +#endif +#ifdef ESRCH + REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH); +#endif +#ifdef EACCES + REGISTER_PCNTL_ERRNO_CONSTANT(EACCES); +#endif +#ifdef EPERM + REGISTER_PCNTL_ERRNO_CONSTANT(EPERM); +#endif +#ifdef ENOMEM + REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM); +#endif +#ifdef E2BIG + REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG); +#endif +#ifdef EFAULT + REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT); +#endif +#ifdef EIO + REGISTER_PCNTL_ERRNO_CONSTANT(EIO); +#endif +#ifdef EISDIR + REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR); +#endif +#ifdef ELIBBAD + REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD); +#endif +#ifdef ELOOP + REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP); +#endif +#ifdef EMFILE + REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE); +#endif +#ifdef ENAMETOOLONG + REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG); +#endif +#ifdef ENFILE + REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE); +#endif +#ifdef ENOENT + REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT); +#endif +#ifdef ENOEXEC + REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC); +#endif +#ifdef ENOTDIR + REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR); +#endif +#ifdef ETXTBSY + REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY); +#endif +} + +static PHP_GINIT_FUNCTION(pcntl) +{ + memset(pcntl_globals, 0, sizeof(*pcntl_globals)); +} + +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; + return SUCCESS; +} + +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); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(pcntl) +{ + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(pcntl) +{ + struct php_pcntl_pending_signal *sig; + + /* FIXME: if a signal is delivered after this point, things will go pear shaped; + * need to remove signal handlers */ + zend_hash_destroy(&PCNTL_G(php_signal_table)); + while (PCNTL_G(head)) { + sig = PCNTL_G(head); + PCNTL_G(head) = sig->next; + efree(sig); + } + while (PCNTL_G(spares)) { + sig = PCNTL_G(spares); + PCNTL_G(spares) = sig->next; + efree(sig); + } + return SUCCESS; +} + +PHP_MINFO_FUNCTION(pcntl) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "pcntl support", "enabled"); + php_info_print_table_end(); +} + +/* {{{ proto int pcntl_fork(void) + Forks the currently running process following the same behavior as the UNIX fork() system call*/ +PHP_FUNCTION(pcntl_fork) +{ + pid_t id; + + id = fork(); + if (id == -1) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno); + } + + RETURN_LONG((long) id); +} +/* }}} */ + +/* {{{ proto int pcntl_alarm(int seconds) + Set an alarm clock for delivery of a signal*/ +PHP_FUNCTION(pcntl_alarm) +{ + long seconds; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE) + return; + + RETURN_LONG ((long) alarm(seconds)); +} +/* }}} */ + +/* {{{ proto int pcntl_waitpid(int pid, int &status, int options) + Waits on or returns the status of a forked child as defined by the waitpid() system call */ +PHP_FUNCTION(pcntl_waitpid) +{ + long pid, options = 0; + zval *z_status = NULL; + int status; + pid_t child_id; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE) + return; + + convert_to_long_ex(&z_status); + + status = Z_LVAL_P(z_status); + + child_id = waitpid((pid_t) pid, &status, options); + + if (child_id < 0) { + PCNTL_G(last_error) = errno; + } + + Z_LVAL_P(z_status) = status; + + RETURN_LONG((long) child_id); +} +/* }}} */ + +/* {{{ proto int pcntl_wait(int &status) + Waits on or returns the status of a forked child as defined by the waitpid() system call */ +PHP_FUNCTION(pcntl_wait) +{ + long options = 0; + zval *z_status = NULL; + int status; + pid_t child_id; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE) + return; + + convert_to_long_ex(&z_status); + + status = Z_LVAL_P(z_status); +#ifdef HAVE_WAIT3 + if(options) { + child_id = wait3(&status, options, NULL); + } + else { + child_id = wait(&status); + } +#else + child_id = wait(&status); +#endif + if (child_id < 0) { + PCNTL_G(last_error) = errno; + } + + Z_LVAL_P(z_status) = status; + + RETURN_LONG((long) child_id); +} +/* }}} */ + +/* {{{ proto bool pcntl_wifexited(int status) + Returns true if the child status code represents a successful exit */ +PHP_FUNCTION(pcntl_wifexited) +{ +#ifdef WIFEXITED + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + if (WIFEXITED(status_word)) + RETURN_TRUE; +#endif + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool pcntl_wifstopped(int status) + Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */ +PHP_FUNCTION(pcntl_wifstopped) +{ +#ifdef WIFSTOPPED + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + if (WIFSTOPPED(status_word)) + RETURN_TRUE; +#endif + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool pcntl_wifsignaled(int status) + Returns true if the child status code represents a process that was terminated due to a signal */ +PHP_FUNCTION(pcntl_wifsignaled) +{ +#ifdef WIFSIGNALED + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + if (WIFSIGNALED(status_word)) + RETURN_TRUE; +#endif + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto int pcntl_wexitstatus(int status) + Returns the status code of a child's exit */ +PHP_FUNCTION(pcntl_wexitstatus) +{ +#ifdef WEXITSTATUS + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + RETURN_LONG(WEXITSTATUS(status_word)); +#else + RETURN_FALSE; +#endif +} +/* }}} */ + +/* {{{ proto int pcntl_wtermsig(int status) + Returns the number of the signal that terminated the process who's status code is passed */ +PHP_FUNCTION(pcntl_wtermsig) +{ +#ifdef WTERMSIG + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + RETURN_LONG(WTERMSIG(status_word)); +#else + RETURN_FALSE; +#endif +} +/* }}} */ + +/* {{{ proto int pcntl_wstopsig(int status) + Returns the number of the signal that caused the process to stop who's status code is passed */ +PHP_FUNCTION(pcntl_wstopsig) +{ +#ifdef WSTOPSIG + long status_word; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) { + return; + } + + RETURN_LONG(WSTOPSIG(status_word)); +#else + RETURN_FALSE; +#endif +} +/* }}} */ + +/* {{{ proto bool pcntl_exec(string path [, array args [, array envs]]) + Executes specified program in current process space as defined by exec(2) */ +PHP_FUNCTION(pcntl_exec) +{ + zval *args = NULL, *envs = NULL; + zval **element; + HashTable *args_hash, *envs_hash; + int argc = 0, argi = 0; + int envc = 0, envi = 0; + int return_val = 0; + char **argv = NULL, **envp = NULL; + char **current_arg, **pair; + int pair_length; + char *key; + uint key_length; + char *path; + int path_len; + ulong key_num; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() > 1) { + /* Build argument list */ + args_hash = HASH_OF(args); + argc = zend_hash_num_elements(args_hash); + + argv = safe_emalloc((argc + 2), sizeof(char *), 0); + *argv = path; + for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1; + (argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS)); + (argi++, current_arg++, zend_hash_move_forward(args_hash)) ) { + + convert_to_string_ex(element); + *current_arg = Z_STRVAL_PP(element); + } + *(current_arg) = NULL; + } else { + argv = emalloc(2 * sizeof(char *)); + *argv = path; + *(argv+1) = NULL; + } + + if ( ZEND_NUM_ARGS() == 3 ) { + /* Build environment pair list */ + envs_hash = HASH_OF(envs); + envc = zend_hash_num_elements(envs_hash); + + envp = safe_emalloc((envc + 1), sizeof(char *), 0); + for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp; + (envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS)); + (envi++, pair++, zend_hash_move_forward(envs_hash)) ) { + switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) { + case HASH_KEY_IS_LONG: + key = emalloc(101); + snprintf(key, 100, "%ld", key_num); + key_length = strlen(key); + break; + case HASH_KEY_NON_EXISTANT: + pair--; + continue; + } + + convert_to_string_ex(element); + + /* Length of element + equal sign + length of key + null */ + pair_length = Z_STRLEN_PP(element) + key_length + 2; + *pair = emalloc(pair_length); + strlcpy(*pair, key, key_length); + strlcat(*pair, "=", pair_length); + strlcat(*pair, Z_STRVAL_PP(element), pair_length); + + /* Cleanup */ + if (return_val == HASH_KEY_IS_LONG) efree(key); + } + *(pair) = NULL; + + if (execve(path, argv, envp) == -1) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno)); + } + + /* Cleanup */ + for (pair = envp; *pair != NULL; pair++) efree(*pair); + efree(envp); + } else { + + if (execv(path, argv) == -1) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno)); + } + } + + efree(argv); + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls]) + Assigns a system signal handler to a PHP function */ +PHP_FUNCTION(pcntl_signal) +{ + zval *handle, **dest_handle = NULL; + char *func_name; + long signo; + zend_bool restart_syscalls = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) { + return; + } + + if (signo < 1 || signo > 32) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid signal"); + RETURN_FALSE; + } + + if (!PCNTL_G(spares)) { + /* since calling malloc() from within a signal handler is not portable, + * pre-allocate a few records for recording signals */ + int i; + for (i = 0; i < 32; i++) { + struct php_pcntl_pending_signal *psig; + + psig = emalloc(sizeof(*psig)); + psig->next = PCNTL_G(spares); + PCNTL_G(spares) = psig; + } + } + + /* Special long value case for SIG_DFL and SIG_IGN */ + if (Z_TYPE_P(handle)==IS_LONG) { + if (Z_LVAL_P(handle) != (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified"); + RETURN_FALSE; + } + if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal"); + RETURN_FALSE; + } + RETURN_TRUE; + } + + if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) { + PCNTL_G(last_error) = EINVAL; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name); + efree(func_name); + RETURN_FALSE; + } + efree(func_name); + + /* Add the function name to our signal table */ + zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle); + if (dest_handle) zval_add_ref(dest_handle); + + if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal"); + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool pcntl_signal_dispatch() + Dispatch signals to signal handlers */ +PHP_FUNCTION(pcntl_signal_dispatch) +{ + pcntl_signal_dispatch(); + RETURN_TRUE; +} +/* }}} */ + +#ifdef HAVE_SIGPROCMASK +/* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset]) + Examine and change blocked signals */ +PHP_FUNCTION(pcntl_sigprocmask) +{ + long how, signo; + zval *user_set, *user_oldset = NULL, **user_signo; + sigset_t set, oldset; + HashPosition pos; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la|z", &how, &user_set, &user_oldset) == FAILURE) { + return; + } + + if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS) + { + if (Z_TYPE_PP(user_signo) != IS_LONG) { + SEPARATE_ZVAL(user_signo); + convert_to_long_ex(user_signo); + } + signo = Z_LVAL_PP(user_signo); + if (sigaddset(&set, signo) != 0) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos); + } + + if (sigprocmask(how, &set, &oldset) != 0) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + + if (user_oldset != NULL) { + if (Z_TYPE_P(user_oldset) != IS_ARRAY) { + zval_dtor(user_oldset); + array_init(user_oldset); + } else { + zend_hash_clean(Z_ARRVAL_P(user_oldset)); + } + for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) { + if (sigismember(&oldset, signo) != 1) { + continue; + } + add_next_index_long(user_oldset, signo); + } + } + + RETURN_TRUE; +} +/* }}} */ +#endif + +#if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT +static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */ +{ + zval *user_set, **user_signo, *user_siginfo = NULL; + long tv_sec = 0, tv_nsec = 0; + sigset_t set; + HashPosition pos; + int signo; + siginfo_t siginfo; + struct timespec timeout; + + if (timedwait) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) { + return; + } + } + + if (sigemptyset(&set) != 0) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS) + { + if (Z_TYPE_PP(user_signo) != IS_LONG) { + SEPARATE_ZVAL(user_signo); + convert_to_long_ex(user_signo); + } + signo = Z_LVAL_PP(user_signo); + if (sigaddset(&set, signo) != 0) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos); + } + + if (timedwait) { + timeout.tv_sec = (time_t) tv_sec; + timeout.tv_nsec = tv_nsec; + signo = sigtimedwait(&set, &siginfo, &timeout); + } else { + signo = sigwaitinfo(&set, &siginfo); + } + if (signo == -1 && errno != EAGAIN) { + PCNTL_G(last_error) = errno; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + } + + /* + * sigtimedwait and sigwaitinfo can return 0 on success on some + * platforms, e.g. NetBSD + */ + if (!signo && siginfo.si_signo) { + signo = siginfo.si_signo; + } + + if (signo > 0 && user_siginfo) { + if (Z_TYPE_P(user_siginfo) != IS_ARRAY) { + zval_dtor(user_siginfo); + array_init(user_siginfo); + } else { + zend_hash_clean(Z_ARRVAL_P(user_siginfo)); + } + add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo); + add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno); + add_assoc_long_ex(user_siginfo, "code", sizeof("code"), siginfo.si_code); + switch(signo) { +#ifdef SIGCHLD + case SIGCHLD: + add_assoc_long_ex(user_siginfo, "status", sizeof("status"), siginfo.si_status); +# ifdef si_utime + add_assoc_double_ex(user_siginfo, "utime", sizeof("utime"), siginfo.si_utime); +# endif +# ifdef si_stime + add_assoc_double_ex(user_siginfo, "stime", sizeof("stime"), siginfo.si_stime); +# endif + add_assoc_long_ex(user_siginfo, "pid", sizeof("pid"), siginfo.si_pid); + add_assoc_long_ex(user_siginfo, "uid", sizeof("uid"), siginfo.si_uid); + break; +#endif + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr); + break; +#ifdef SIGPOLL + case SIGPOLL: + add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band); +# ifdef si_fd + add_assoc_long_ex(user_siginfo, "fd", sizeof("fd"), siginfo.si_fd); +# endif + break; +#endif + EMPTY_SWITCH_DEFAULT_CASE(); + } + } + + 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 + +#ifdef HAVE_GETPRIORITY +/* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]]) + Get the priority of any process */ +PHP_FUNCTION(pcntl_getpriority) +{ + long who = PRIO_PROCESS; + long pid = getpid(); + int pri; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) { + RETURN_FALSE; + } + + /* needs to be cleared, since any returned value is valid */ + errno = 0; + + pri = getpriority(who, pid); + + if (errno) { + PCNTL_G(last_error) = errno; + switch (errno) { + case ESRCH: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno); + break; + case EINVAL: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno); + break; + } + RETURN_FALSE; + } + + RETURN_LONG(pri); +} +/* }}} */ +#endif + +#ifdef HAVE_SETPRIORITY +/* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]]) + Change the priority of any process */ +PHP_FUNCTION(pcntl_setpriority) +{ + long who = PRIO_PROCESS; + long pid = getpid(); + long pri; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) { + RETURN_FALSE; + } + + if (setpriority(who, pid, pri)) { + PCNTL_G(last_error) = errno; + switch (errno) { + case ESRCH: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno); + break; + case EINVAL: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno); + break; + case EPERM: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: A process was located, but neither its effective nor real user ID matched the effective user ID of the caller", errno); + break; + case EACCES: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno); + break; + } + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ +#endif + +/* {{{ proto int pcntl_get_last_error(void) + Retrieve the error number set by the last pcntl function which failed. */ +PHP_FUNCTION(pcntl_get_last_error) +{ + RETURN_LONG(PCNTL_G(last_error)); +} +/* }}} */ + +/* {{{ proto string pcntl_strerror(int errno) + Retrieve the system error message associated with the given errno. */ +PHP_FUNCTION(pcntl_strerror) +{ + long error; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) { + RETURN_FALSE; + } + + RETURN_STRING(strerror(error), 1); +} +/* }}} */ + +/* Our custom signal handler that calls the appropriate php_function */ +static void pcntl_signal_handler(int signo) +{ + struct php_pcntl_pending_signal *psig; + TSRMLS_FETCH(); + + psig = PCNTL_G(spares); + if (!psig) { + /* oops, too many signals for us to track, so we'll forget about this one */ + return; + } + PCNTL_G(spares) = psig->next; + + psig->signo = signo; + psig->next = NULL; + + /* the head check is important, as the tick handler cannot atomically clear both + * the head and tail */ + if (PCNTL_G(head) && PCNTL_G(tail)) { + PCNTL_G(tail)->next = psig; + } else { + PCNTL_G(head) = psig; + } + PCNTL_G(tail) = psig; +} + +void pcntl_signal_dispatch() +{ + zval *param, **handle, *retval; + struct php_pcntl_pending_signal *queue, *next; + sigset_t mask; + sigset_t old_mask; + TSRMLS_FETCH(); + + /* Mask all signals */ + 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)) { + sigprocmask(SIG_SETMASK, &old_mask, NULL); + return; + } + + /* Prevent reentrant handler calls */ + PCNTL_G(processing_signal_queue) = 1; + + queue = PCNTL_G(head); + PCNTL_G(head) = NULL; /* simple stores are atomic */ + + /* Allocate */ + + while (queue) { + if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) { + MAKE_STD_ZVAL(retval); + MAKE_STD_ZVAL(param); + 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, ¶m TSRMLS_CC); + zval_ptr_dtor(¶m); + zval_ptr_dtor(&retval); + } + + next = queue->next; + queue->next = PCNTL_G(spares); + PCNTL_G(spares) = queue; + queue = next; + } + + /* Re-enable queue */ + PCNTL_G(processing_signal_queue) = 0; + + /* return signal mask to previous state */ + sigprocmask(SIG_SETMASK, &old_mask, NULL); +} + + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/ext/pcntl/php_pcntl.h b/ext/pcntl/php_pcntl.h new file mode 100644 index 0000000..280a45b --- /dev/null +++ b/ext/pcntl/php_pcntl.h @@ -0,0 +1,91 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jason Greene <jason@inetgurus.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef PHP_PCNTL_H +#define PHP_PCNTL_H + +extern zend_module_entry pcntl_module_entry; +#define phpext_pcntl_ptr &pcntl_module_entry + +PHP_MINIT_FUNCTION(pcntl); +PHP_MSHUTDOWN_FUNCTION(pcntl); +PHP_RINIT_FUNCTION(pcntl); +PHP_RSHUTDOWN_FUNCTION(pcntl); +PHP_MINFO_FUNCTION(pcntl); + +PHP_FUNCTION(pcntl_alarm); +PHP_FUNCTION(pcntl_fork); +PHP_FUNCTION(pcntl_waitpid); +PHP_FUNCTION(pcntl_wait); +PHP_FUNCTION(pcntl_wifexited); +PHP_FUNCTION(pcntl_wifstopped); +PHP_FUNCTION(pcntl_wifsignaled); +PHP_FUNCTION(pcntl_wexitstatus); +PHP_FUNCTION(pcntl_wtermsig); +PHP_FUNCTION(pcntl_wstopsig); +PHP_FUNCTION(pcntl_signal); +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 +PHP_FUNCTION(pcntl_sigwaitinfo); +PHP_FUNCTION(pcntl_sigtimedwait); +#endif +PHP_FUNCTION(pcntl_exec); +#ifdef HAVE_GETPRIORITY +PHP_FUNCTION(pcntl_getpriority); +#endif +#ifdef HAVE_SETPRIORITY +PHP_FUNCTION(pcntl_setpriority); +#endif + +struct php_pcntl_pending_signal { + struct php_pcntl_pending_signal *next; + long signo; +}; + +ZEND_BEGIN_MODULE_GLOBALS(pcntl) + HashTable php_signal_table; + int processing_signal_queue; + struct php_pcntl_pending_signal *head, *tail, *spares; + int last_error; +ZEND_END_MODULE_GLOBALS(pcntl) + +#ifdef ZTS +#define PCNTL_G(v) TSRMG(pcntl_globals_id, zend_pcntl_globals *, v) +#else +#define PCNTL_G(v) (pcntl_globals.v) +#endif + +#define REGISTER_PCNTL_ERRNO_CONSTANT(name) REGISTER_LONG_CONSTANT("PCNTL_" #name, name, CONST_CS | CONST_PERSISTENT) + +#endif /* PHP_PCNTL_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/ext/pcntl/php_signal.c b/ext/pcntl/php_signal.c new file mode 100644 index 0000000..7e123a1 --- /dev/null +++ b/ext/pcntl/php_signal.c @@ -0,0 +1,75 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jason Greene <jason@inetgurus.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "TSRM.h" +#include "php_signal.h" +#include "Zend/zend.h" +#include "Zend/zend_signal.h" + +/* php_signal using sigaction is derrived from Advanced Programing + * in the Unix Environment by W. Richard Stevens p 298. */ +Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all) +{ + struct sigaction act,oact; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + act.sa_handler = func; + + if (mask_all) { + sigfillset(&act.sa_mask); + } else { + sigemptyset(&act.sa_mask); + } + act.sa_flags = 0; + if (signo == SIGALRM || (! restart)) { +#ifdef SA_INTERRUPT + act.sa_flags |= SA_INTERRUPT; /* SunOS */ +#endif + } else { +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ +#endif + } +#ifdef ZEND_SIGNALS + if (zend_sigaction(signo, &act, &oact TSRMLS_CC) < 0) +#else + if (sigaction(signo, &act, &oact) < 0) +#endif + { + return SIG_ERR; + } + + return oact.sa_handler; +} + +Sigfunc *php_signal(int signo, Sigfunc *func, int restart) +{ + return php_signal4(signo, func, restart, 0); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/pcntl/php_signal.h b/ext/pcntl/php_signal.h new file mode 100644 index 0000000..07bde63 --- /dev/null +++ b/ext/pcntl/php_signal.h @@ -0,0 +1,36 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jason Greene <jason@inetgurus.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include <signal.h> +#ifndef PHP_SIGNAL_H +#define PHP_SIGNAL_H + +#ifndef NSIG +# define NSIG 32 +#endif +#ifndef SIGRTMAX +# define SIGRTMAX 64 +#endif + +typedef void Sigfunc(int); +Sigfunc *php_signal(int signo, Sigfunc *func, int restart); +Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all); + +#endif diff --git a/ext/pcntl/test-pcntl.php b/ext/pcntl/test-pcntl.php new file mode 100755 index 0000000..01d44fc --- /dev/null +++ b/ext/pcntl/test-pcntl.php @@ -0,0 +1,40 @@ +#!../../php -q +<? + +declare(ticks=1); + +function alarm_handle($signal){ + if ($signal==SIGALRM) print "Child: Caught SIGALRM!!!\n"; +} + +function usr1_handle($signal){ + if ($signal==SIGUSR1) print "Child: Caught SIGUSR1!!!\n"; +} + +print "This test will demonstrate a fork followed by ipc via signals.\n"; + +$pid=pcntl_fork(); +if ($pid==0) { + pcntl_signal(SIGUSR1, "usr1_handle"); + pcntl_signal(SIGALRM, "alarm_handle"); + print "Child: Waiting for alarm.....\n"; + sleep(100); + print "Child: Waiting for usr1......\n"; + sleep(100); + print "Child: Resetting Alarm handler to Ignore....\n"; + pcntl_signal(SIGALRM, SIG_IGN); + print "Child: sleeping for 10 seconds....\n"; + sleep(10); + print "Done\n"; +} else { + print "Parent: Waiting 10 seconds....\n"; + sleep(10); + print "Parent: Sending SIGALRM to Child\n"; + posix_kill($pid,SIGALRM); + sleep(1); + print "Parent: Senging SIGUSR1 to Child\n"; + posix_kill($pid,SIGUSR1); + sleep(2); + print "Parent: Sending SIGALRM to Child\n"; + pcntl_waitpid($pid, &$status, $options); +} diff --git a/ext/pcntl/tests/001.phpt b/ext/pcntl/tests/001.phpt new file mode 100644 index 0000000..fb1006e --- /dev/null +++ b/ext/pcntl/tests/001.phpt @@ -0,0 +1,82 @@ +--TEST-- +Test pcntl wait functionality +--SKIPIF-- +<?php + if (!extension_loaded("pcntl")) print "skip"; + elseif (!function_exists("posix_kill")) print "skip posix_kill() not available"; +?> +--FILE-- +<?php +function test_exit_waits(){ + print "\n\nTesting pcntl_wifexited and wexitstatus...."; + + $pid=pcntl_fork(); + if ($pid==0) { + sleep(1); + exit(-1); + } else { + $options=0; + pcntl_waitpid($pid, $status, $options); + if ( pcntl_wifexited($status) ) print "\nExited With: ". pcntl_wexitstatus($status); + } +} + +function test_exit_signal(){ + print "\n\nTesting pcntl_wifsignaled...."; + + $pid=pcntl_fork(); + + if ($pid==0) { + sleep(10); + exit; + } else { + $options=0; + posix_kill($pid, SIGTERM); + pcntl_waitpid($pid, $status, $options); + if ( pcntl_wifsignaled($status) ) { + $signal_print=pcntl_wtermsig($status); + if ($signal_print==SIGTERM) $signal_print="SIGTERM"; + print "\nProcess was terminated by signal : ". $signal_print; + } + + } +} + + +function test_stop_signal(){ + print "\n\nTesting pcntl_wifstopped and pcntl_wstopsig...."; + + $pid=pcntl_fork(); + + if ($pid==0) { + sleep(1); + exit; + } else { + $options=WUNTRACED; + posix_kill($pid, SIGSTOP); + pcntl_waitpid($pid, $status, $options); + if ( pcntl_wifstopped($status) ) { + $signal_print=pcntl_wstopsig($status); + if ($signal_print==SIGSTOP) $signal_print="SIGSTOP"; + print "\nProcess was stoped by signal : ". $signal_print; + } + posix_kill($pid, SIGCONT); + } +} + +print "Staring wait.h tests...."; +test_exit_waits(); +test_exit_signal(); +test_stop_signal(); +?> +--EXPECT-- +Staring wait.h tests.... + +Testing pcntl_wifexited and wexitstatus.... +Exited With: 255 + +Testing pcntl_wifsignaled.... +Process was terminated by signal : SIGTERM + +Testing pcntl_wifstopped and pcntl_wstopsig.... +Process was stoped by signal : SIGSTOP diff --git a/ext/pcntl/tests/002.phpt b/ext/pcntl/tests/002.phpt new file mode 100644 index 0000000..3cec883 --- /dev/null +++ b/ext/pcntl/tests/002.phpt @@ -0,0 +1,103 @@ +--TEST-- +pcntl: pcntl_sigprocmask(), pcntl_sigwaitinfo(), pcntl_sigtimedwait() +--SKIPIF-- +<?php + if (!extension_loaded('pcntl')) die('skip pcntl extension not available'); + elseif (!extension_loaded('posix')) die('skip posix extension not available'); + elseif (!function_exists('pcntl_sigwaitinfo') or !function_exists('pcntl_sigtimedwait')) die('skip required functionality is not available'); + elseif (!defined('CLD_EXITED')) die('skip CLD_EXITED not defined'); +?> +--FILE-- +<?php + +$pid = pcntl_fork(); +if ($pid == -1) { + die('failed'); +} else if ($pid) { + pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD,(string)SIGTERM)); + $oldset = array(); + pcntl_sigprocmask(SIG_BLOCK, array(), $oldset); + var_dump(in_array(SIGCHLD, $oldset)); + var_dump(in_array(SIGTERM, $oldset)); + + posix_kill(posix_getpid(), SIGTERM); + $signo = pcntl_sigwaitinfo(array(SIGTERM), $siginfo); + echo "signo == SIGTERM\n"; + var_dump($signo === SIGTERM && $signo === $siginfo['signo']); + echo "code === SI_USER || SI_NOINFO\n"; + if (defined('SI_NOINFO')) { + var_dump(($siginfo['code'] === SI_USER) || ($siginfo['code'] === SI_NOINFO)); + } else { + var_dump($siginfo['code'] === SI_USER); + } + + pcntl_signal(SIGCHLD, function($signo){}); + posix_kill($pid, SIGTERM); + $signo = pcntl_sigwaitinfo(array((string)SIGCHLD), $siginfo); + echo "signo == SIGCHLD\n"; + var_dump($signo === SIGCHLD && $signo === $siginfo['signo']); + echo "code === CLD_KILLED\n"; + var_dump($siginfo['code'] === CLD_KILLED); + echo "signo === SIGCHLD\n"; + var_dump($siginfo['signo'] === SIGCHLD); + echo "signo === uid\n"; + var_dump($siginfo['uid'] === posix_getuid()); + echo "signo === pid\n"; + var_dump($siginfo['pid'] === $pid); + pcntl_waitpid($pid, $status); + + set_error_handler(function($errno, $errstr) { echo "Error triggered\n"; }, E_WARNING); + + echo "sigprocmask with invalid arguments\n"; + + /* Valgrind expectedly complains about this: + * "sigprocmask: unknown 'how' field 2147483647" + * Skip */ + if (getenv("USE_ZEND_ALLOC") !== '0') { + var_dump(pcntl_sigprocmask(PHP_INT_MAX, array(SIGTERM))); + } else { + echo "Error triggered\n"; + echo "bool(false)\n"; + } + var_dump(pcntl_sigprocmask(SIG_SETMASK, array(0))); + + echo "sigwaitinfo with invalid arguments\n"; + var_dump(pcntl_sigwaitinfo(array(0))); + + echo "sigtimedwait with invalid arguments\n"; + var_dump(pcntl_sigtimedwait(array(SIGTERM), $signo, PHP_INT_MAX, PHP_INT_MAX)); +} else { + $siginfo = NULL; + pcntl_sigtimedwait(array(SIGINT), $siginfo, 3600, 0); + exit; +} + +?> +--EXPECTF-- +bool(true) +bool(true) +signo == SIGTERM +bool(true) +code === SI_USER || SI_NOINFO +bool(true) +signo == SIGCHLD +bool(true) +code === CLD_KILLED +bool(true) +signo === SIGCHLD +bool(true) +signo === uid +bool(true) +signo === pid +bool(true) +sigprocmask with invalid arguments +Error triggered +bool(false) +Error triggered +bool(false) +sigwaitinfo with invalid arguments +Error triggered +bool(false) +sigtimedwait with invalid arguments +Error triggered +int(-1) diff --git a/ext/pcntl/tests/003.phpt b/ext/pcntl/tests/003.phpt new file mode 100644 index 0000000..012277d --- /dev/null +++ b/ext/pcntl/tests/003.phpt @@ -0,0 +1,32 @@ +--TEST-- +pcntl: SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK +--SKIPIF-- +<?php + if (!extension_loaded('pcntl')) die('skip pcntl extension not available'); + elseif (!extension_loaded('posix')) die('skip posix extension not available'); + elseif (!function_exists('pcntl_sigwaitinfo') or !function_exists('pcntl_sigtimedwait')) die('skip required functionality is not available'); +?> +--FILE-- +<?php + +pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD,SIGTERM), $old); +var_dump(count($old)); +pcntl_sigprocmask(SIG_BLOCK, array(SIGINT), $old); +var_dump(count($old)); +pcntl_sigprocmask(SIG_UNBLOCK, array(SIGINT), $old); +var_dump(count($old)); +pcntl_sigprocmask(SIG_SETMASK, array(SIGINT), $old); +var_dump(count($old)); +pcntl_sigprocmask(SIG_SETMASK, array(), $old); +var_dump(count($old)); +pcntl_sigprocmask(SIG_SETMASK, array(), $old); +var_dump(count($old)); + +?> +--EXPECT-- +int(0) +int(2) +int(3) +int(2) +int(1) +int(0) diff --git a/ext/pcntl/tests/bug47566.phpt b/ext/pcntl/tests/bug47566.phpt new file mode 100644 index 0000000..6eb3dbc --- /dev/null +++ b/ext/pcntl/tests/bug47566.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #47566 (return value of pcntl_wexitstatus()) +--SKIPIF-- +<?php if (!extension_loaded("pcntl")) print "skip"; ?> +--FILE-- +<?php +$pid = pcntl_fork(); +if ($pid == -1) { + echo "Unable to fork"; + exit; +} elseif ($pid) { + $epid = pcntl_waitpid(-1,$status); + var_dump(pcntl_wexitstatus($status)); +} else { + exit(128); +} +?> +--EXPECT-- +int(128) diff --git a/ext/pcntl/tests/pcntl_alarm.phpt b/ext/pcntl/tests/pcntl_alarm.phpt new file mode 100644 index 0000000..a9cae16 --- /dev/null +++ b/ext/pcntl/tests/pcntl_alarm.phpt @@ -0,0 +1,23 @@ +--TEST-- +pcntl_alarm() +--SKIPIF-- +<?php if (!function_exists("pcntl_sigtimedwait")) die("skip pcntl_sigtimedwait() not available"); ?> +--INI-- +max_execution_time=0 +--FILE-- +<?php +pcntl_signal(SIGALRM, function(){}); + +var_dump(pcntl_alarm()); +pcntl_alarm(0); +var_dump(pcntl_alarm(60)); +var_dump(pcntl_alarm(1) > 0); +$siginfo = array(); +var_dump(pcntl_sigtimedwait(array(SIGALRM),$siginfo,2) === SIGALRM); +?> +--EXPECTF-- +Warning: pcntl_alarm() expects exactly 1 parameter, 0 given in %s +NULL +int(0) +bool(true) +bool(true) diff --git a/ext/pcntl/tests/pcntl_exec.phpt b/ext/pcntl/tests/pcntl_exec.phpt new file mode 100644 index 0000000..9d2ec1d --- /dev/null +++ b/ext/pcntl/tests/pcntl_exec.phpt @@ -0,0 +1,15 @@ +--TEST-- +pcntl_exec() +--SKIPIF-- +<?php +if (!extension_loaded("pcntl")) print "skip"; +if (!getenv("TEST_PHP_EXECUTABLE") || !is_executable(getenv("TEST_PHP_EXECUTABLE"))) die("skip TEST_PHP_EXECUTABLE not set"); +?> +--FILE-- +<?php +echo "ok\n"; +pcntl_exec(getenv("TEST_PHP_EXECUTABLE")); +echo "nok\n"; +?> +--EXPECT-- +ok diff --git a/ext/pcntl/tests/pcntl_exec_2.phpt b/ext/pcntl/tests/pcntl_exec_2.phpt new file mode 100644 index 0000000..02b5e22 --- /dev/null +++ b/ext/pcntl/tests/pcntl_exec_2.phpt @@ -0,0 +1,27 @@ +--TEST-- +pcntl_exec() 2 +--SKIPIF-- +<?php + +if (!extension_loaded("pcntl")) print "skip"; +if (!getenv("TEST_PHP_EXECUTABLE") || !is_executable(getenv("TEST_PHP_EXECUTABLE"))) die("skip TEST_PHP_EXECUTABLE not set"); + +?> +--FILE-- +<?php +if (getenv("PCNTL_EXEC_TEST_IS_CHILD")) { + var_dump((binary)getenv("FOO")); + exit; +} +echo "ok\n"; +pcntl_exec(getenv("TEST_PHP_EXECUTABLE"), array(__FILE__), array( + b"PCNTL_EXEC_TEST_IS_CHILD" => b"1", + b"FOO" => b"BAR", + 1 => b"long") +); + +echo "nok\n"; +?> +--EXPECT-- +ok +string(3) "BAR" diff --git a/ext/pcntl/tests/pcntl_exec_3.phpt b/ext/pcntl/tests/pcntl_exec_3.phpt new file mode 100644 index 0000000..5349381 --- /dev/null +++ b/ext/pcntl/tests/pcntl_exec_3.phpt @@ -0,0 +1,17 @@ +--TEST-- +pcntl_exec() 3 +--SKIPIF-- +<?php if (!extension_loaded("pcntl")) print "skip"; ?> +--FILE-- +<?php +var_dump(pcntl_exec()); +$file = tempnam(sys_get_temp_dir(),"php"); +var_dump(pcntl_exec($file, array("foo","bar"), array("foo" => "bar"))); +unlink($file); +?> +--EXPECTF-- +Warning: pcntl_exec() expects at least 1 parameter, 0 given %s +NULL + +Warning: pcntl_exec(): Error has occurred: (errno %d) %s +bool(false) diff --git a/ext/pcntl/tests/pcntl_fork_basic.phpt b/ext/pcntl/tests/pcntl_fork_basic.phpt new file mode 100644 index 0000000..b1e2a9b --- /dev/null +++ b/ext/pcntl/tests/pcntl_fork_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test function pcntl_fork() by calling it with its expected arguments +--CREDITS-- +Marco Fabbri mrfabbri@gmail.com +Francesco Fullone ff@ideato.it +#PHPTestFest Cesena Italia on 2009-06-20 +--SKIPIF-- +<?php + if (!extension_loaded('pcntl')) die('skip pcntl extension not available'); + elseif (!extension_loaded('posix')) die('skip posix extension not available'); +?> +--FILE-- +<?php +echo "*** Test by calling method or function with its expected arguments, first print the child PID and the father ***\n"; + +$pid = pcntl_fork(); +if ($pid > 0) { + pcntl_wait($status); + var_dump($pid); +} else { + var_dump($pid); +} +?> +--EXPECTF-- +*** Test by calling method or function with its expected arguments, first print the child PID and the father *** +int(0) +int(%d) diff --git a/ext/pcntl/tests/pcntl_fork_variation.phpt b/ext/pcntl/tests/pcntl_fork_variation.phpt new file mode 100644 index 0000000..4eea071 --- /dev/null +++ b/ext/pcntl/tests/pcntl_fork_variation.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test function pcntl_fork() by testing the process isolation in the forking hierarchy father -> son -> grandson where father can not knows his grandson +--CREDITS-- +Marco Fabbri mrfabbri@gmail.com +Francesco Fullone ff@ideato.it +#PHPTestFest Cesena Italia on 2009-06-20 +--SKIPIF-- +<?php + if (!extension_loaded('pcntl')) die('skip pcntl extension not available'); + elseif (!extension_loaded('posix')) die('skip posix extension not available'); +?> +--FILE-- +<?php +echo "*** Testing the process isolations between a process and its forks ***\n"; + +$pid = pcntl_fork(); + +if ($pid > 0) { + pcntl_wait($status); + echo "father is $pid\n"; + + if (!isset($pid2)) + { + echo "father ($pid) doesn't know its grandsons\n"; + } +} +else +{ + echo "son ($pid)\n"; + $pid2 = pcntl_fork(); + if ($pid2 > 0) + { + pcntl_wait($status2); + echo "son is father of $pid2\n"; + } + else + { + echo "grandson ($pid2)\n"; + } +} +?> +--EXPECTF-- +*** Testing the process isolations between a process and its forks *** +son (0) +grandson (0) +son is father of %d +father is %d +father (%d) doesn't know its grandsons diff --git a/ext/pcntl/tests/pcntl_get_last_error.phpt b/ext/pcntl/tests/pcntl_get_last_error.phpt new file mode 100644 index 0000000..4ed66c9 --- /dev/null +++ b/ext/pcntl/tests/pcntl_get_last_error.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test pcntl_get_last_error() +--SKIPIF-- +<?php + if (!extension_loaded("pcntl")) print "skip"; +?> +--FILE-- +<?php +var_dump(pcntl_get_last_error()); +$pid = pcntl_wait($status); +var_dump($pid); +var_dump(pcntl_get_last_error() == PCNTL_ECHILD); +?> +--EXPECT-- +int(0) +int(-1) +bool(true) diff --git a/ext/pcntl/tests/pcntl_signal.phpt b/ext/pcntl/tests/pcntl_signal.phpt new file mode 100644 index 0000000..2db0130 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal.phpt @@ -0,0 +1,40 @@ +--TEST-- +pcntl_signal() +--SKIPIF-- +<?php if (!extension_loaded("pcntl")) print "skip"; ?> +<?php if (!extension_loaded("posix")) die("skip posix extension not available"); ?> +--FILE-- +<?php +pcntl_signal(SIGTERM, function($signo){ + echo "signal dispatched\n"; +}); +posix_kill(posix_getpid(), SIGTERM); +pcntl_signal_dispatch(); + +var_dump(pcntl_signal()); +var_dump(pcntl_signal(SIGALRM, SIG_IGN)); +var_dump(pcntl_signal(-1, -1)); +var_dump(pcntl_signal(-1, function(){})); +var_dump(pcntl_signal(SIGALRM, "not callable")); + + +/* test freeing queue in RSHUTDOWN */ +posix_kill(posix_getpid(), SIGTERM); +echo "ok\n"; +?> +--EXPECTF-- +signal dispatched + +Warning: pcntl_signal() expects at least 2 parameters, 0 given in %s +NULL +bool(true) + +Warning: pcntl_signal(): Invalid signal %s +bool(false) + +Warning: pcntl_signal(): Invalid signal %s +bool(false) + +Warning: pcntl_signal(): not callable is not a callable function name error in %s +bool(false) +ok diff --git a/ext/pcntl/tests/pcntl_signal_dispatch.phpt b/ext/pcntl/tests/pcntl_signal_dispatch.phpt new file mode 100644 index 0000000..acf6cc0 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_dispatch.phpt @@ -0,0 +1,26 @@ +--TEST-- +pcnt_signal_dispatch() +--SKIPIF-- +<?php + if (!extension_loaded("pcntl")) print "skip"; + elseif (!function_exists("pcntl_signal")) print "skip pcntl_signal() not available"; + elseif (!function_exists("pcntl_signal_dispatch")) print "skip pcntl_signal_dispatch() 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_signal(SIGTERM, function ($signo) { echo "Signal handler called!\n"; }); + +echo "Start!\n"; +posix_kill(posix_getpid(), SIGTERM); +$i = 0; // dummy +pcntl_signal_dispatch(); +echo "Done!\n"; + +?> +--EXPECTF-- +Start! +Signal handler called! +Done! diff --git a/ext/pcntl/tests/pcntl_wait.phpt b/ext/pcntl/tests/pcntl_wait.phpt new file mode 100644 index 0000000..c304c84 --- /dev/null +++ b/ext/pcntl/tests/pcntl_wait.phpt @@ -0,0 +1,66 @@ +--TEST-- +pcntl_wait() +--SKIPIF-- +<?php if (!extension_loaded("pcntl")) print "skip"; ?> +<?php if (!extension_loaded("posix")) die("skip posix extension not available"); ?> +--FILE-- +<?php +$pid = pcntl_fork(); +if ($pid == 1) { + die("failed"); +} else if ($pid) { + $status = 0; + pcntl_wait($status, WUNTRACED); + var_dump(pcntl_wifexited($status)); + posix_kill($pid, SIGCONT); + + pcntl_wait($status); + var_dump(pcntl_wifsignaled($status)); + var_dump(pcntl_wifstopped($status)); + var_dump(pcntl_wexitstatus($status)); + + var_dump(pcntl_wait($status, WNOHANG | WUNTRACED)); + var_dump(pcntl_wait()); + var_dump(pcntl_waitpid()); + + var_dump(pcntl_wifexited()); + var_dump(pcntl_wifstopped()); + var_dump(pcntl_wifsignaled()); + var_dump(pcntl_wexitstatus()); + var_dump(pcntl_wtermsig()); + var_dump(pcntl_wstopsig()); +} else { + posix_kill(posix_getpid(), SIGSTOP); + exit(42); +} +?> +--EXPECTF-- +bool(false) +bool(false) +bool(false) +int(42) +int(-1) + +Warning: pcntl_wait() expects at least 1 parameter, 0 given in %s +NULL + +Warning: pcntl_waitpid() expects at least 2 parameters, 0 given in %s +NULL + +Warning: pcntl_wifexited() expects exactly 1 parameter, 0 given in %s +NULL + +Warning: pcntl_wifstopped() expects exactly 1 parameter, 0 given in %s +NULL + +Warning: pcntl_wifsignaled() expects exactly 1 parameter, 0 given in %s +NULL + +Warning: pcntl_wexitstatus() expects exactly 1 parameter, 0 given in %s +NULL + +Warning: pcntl_wtermsig() expects exactly 1 parameter, 0 given in %s +NULL + +Warning: pcntl_wstopsig() expects exactly 1 parameter, 0 given in %s +NULL diff --git a/ext/pcntl/tests/signal_closure_handler.phpt b/ext/pcntl/tests/signal_closure_handler.phpt new file mode 100644 index 0000000..438e051 --- /dev/null +++ b/ext/pcntl/tests/signal_closure_handler.phpt @@ -0,0 +1,25 @@ +--TEST-- +Closures as a signal handler +--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 +declare (ticks = 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! |