Back to index

php5  5.3.10
pcntl.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Jason Greene <jason@inetgurus.net>                           |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: pcntl.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #define PCNTL_DEBUG 0
00022 
00023 #if PCNTL_DEBUG
00024 #define DEBUG_OUT printf("DEBUG: ");printf
00025 #define IF_DEBUG(z) z
00026 #else
00027 #define IF_DEBUG(z)
00028 #endif
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include "config.h"
00032 #endif
00033 
00034 #include "php.h"
00035 #include "php_ini.h"
00036 #include "ext/standard/info.h"
00037 #include "php_pcntl.h"
00038 #include "php_signal.h"
00039 #include "php_ticks.h"
00040 
00041 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
00042 #include <sys/wait.h>
00043 #include <sys/time.h>
00044 #include <sys/resource.h>
00045 #endif
00046 
00047 #include <errno.h>
00048 
00049 ZEND_DECLARE_MODULE_GLOBALS(pcntl)
00050 static PHP_GINIT_FUNCTION(pcntl);
00051 
00052 /* {{{ arginfo */
00053 ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0)
00054 ZEND_END_ARG_INFO()
00055 
00056 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
00057        ZEND_ARG_INFO(0, pid)
00058        ZEND_ARG_INFO(1, status)
00059        ZEND_ARG_INFO(0, options)
00060 ZEND_END_ARG_INFO()
00061 
00062 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
00063        ZEND_ARG_INFO(1, status)
00064        ZEND_ARG_INFO(0, options)
00065 ZEND_END_ARG_INFO()
00066 
00067 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
00068        ZEND_ARG_INFO(0, signo)
00069        ZEND_ARG_INFO(0, handler)
00070        ZEND_ARG_INFO(0, restart_syscalls)
00071 ZEND_END_ARG_INFO()
00072 
00073 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
00074        ZEND_ARG_INFO(0, how)
00075        ZEND_ARG_INFO(0, set)
00076        ZEND_ARG_INFO(1, oldset)
00077 ZEND_END_ARG_INFO()
00078 
00079 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
00080        ZEND_ARG_INFO(0, set)
00081        ZEND_ARG_INFO(1, info)
00082 ZEND_END_ARG_INFO()
00083 
00084 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
00085        ZEND_ARG_INFO(0, set)
00086        ZEND_ARG_INFO(1, info)
00087        ZEND_ARG_INFO(0, seconds)
00088        ZEND_ARG_INFO(0, nanoseconds)
00089 ZEND_END_ARG_INFO()
00090 
00091 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
00092        ZEND_ARG_INFO(0, status)
00093 ZEND_END_ARG_INFO()
00094 
00095 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1)
00096        ZEND_ARG_INFO(0, status)
00097 ZEND_END_ARG_INFO()
00098 
00099 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1)
00100        ZEND_ARG_INFO(0, status)
00101 ZEND_END_ARG_INFO()
00102 
00103 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1)
00104        ZEND_ARG_INFO(0, status)
00105 ZEND_END_ARG_INFO()
00106 
00107 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1)
00108        ZEND_ARG_INFO(0, status)
00109 ZEND_END_ARG_INFO()
00110 
00111 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1)
00112        ZEND_ARG_INFO(0, status)
00113 ZEND_END_ARG_INFO()
00114 
00115 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1)
00116        ZEND_ARG_INFO(0, path)
00117        ZEND_ARG_INFO(0, args)
00118        ZEND_ARG_INFO(0, envs)
00119 ZEND_END_ARG_INFO()
00120 
00121 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1)
00122        ZEND_ARG_INFO(0, seconds)
00123 ZEND_END_ARG_INFO()
00124 
00125 #ifdef HAVE_GETPRIORITY
00126 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0)
00127        ZEND_ARG_INFO(0, pid)
00128        ZEND_ARG_INFO(0, process_identifier)
00129 ZEND_END_ARG_INFO()
00130 #endif
00131 
00132 #ifdef HAVE_SETPRIORITY
00133 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
00134        ZEND_ARG_INFO(0, priority)
00135        ZEND_ARG_INFO(0, pid)
00136        ZEND_ARG_INFO(0, process_identifier)
00137 ZEND_END_ARG_INFO()
00138 #endif
00139 
00140 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
00141         ZEND_ARG_INFO(0, errno)
00142 ZEND_END_ARG_INFO()
00143 /* }}} */
00144 
00145 const zend_function_entry pcntl_functions[] = {
00146        PHP_FE(pcntl_fork,                 arginfo_pcntl_void)
00147        PHP_FE(pcntl_waitpid,              arginfo_pcntl_waitpid)
00148        PHP_FE(pcntl_wait,                 arginfo_pcntl_wait)
00149        PHP_FE(pcntl_signal,        arginfo_pcntl_signal)
00150        PHP_FE(pcntl_signal_dispatch,      arginfo_pcntl_void)
00151        PHP_FE(pcntl_wifexited,            arginfo_pcntl_wifexited)
00152        PHP_FE(pcntl_wifstopped,    arginfo_pcntl_wifstopped)
00153        PHP_FE(pcntl_wifsignaled,   arginfo_pcntl_wifsignaled)
00154        PHP_FE(pcntl_wexitstatus,   arginfo_pcntl_wifexitstatus)
00155        PHP_FE(pcntl_wtermsig,             arginfo_pcntl_wtermsig)
00156        PHP_FE(pcntl_wstopsig,             arginfo_pcntl_wstopsig)
00157        PHP_FE(pcntl_exec,                 arginfo_pcntl_exec)
00158        PHP_FE(pcntl_alarm,                arginfo_pcntl_alarm)
00159        PHP_FE(pcntl_get_last_error,       arginfo_pcntl_void)
00160        PHP_FALIAS(pcntl_errno, pcntl_get_last_error,    NULL)
00161        PHP_FE(pcntl_strerror,             arginfo_pcntl_strerror)
00162 #ifdef HAVE_GETPRIORITY
00163        PHP_FE(pcntl_getpriority,   arginfo_pcntl_getpriority)
00164 #endif
00165 #ifdef HAVE_SETPRIORITY
00166        PHP_FE(pcntl_setpriority,   arginfo_pcntl_setpriority)
00167 #endif
00168 #ifdef HAVE_SIGPROCMASK
00169        PHP_FE(pcntl_sigprocmask,   arginfo_pcntl_sigprocmask)
00170 #endif
00171 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
00172        PHP_FE(pcntl_sigwaitinfo,   arginfo_pcntl_sigwaitinfo)
00173        PHP_FE(pcntl_sigtimedwait,  arginfo_pcntl_sigtimedwait)
00174 #endif
00175        PHP_FE_END
00176 };
00177 
00178 zend_module_entry pcntl_module_entry = {
00179        STANDARD_MODULE_HEADER,
00180        "pcntl",
00181        pcntl_functions,
00182        PHP_MINIT(pcntl),
00183        PHP_MSHUTDOWN(pcntl),
00184        PHP_RINIT(pcntl),
00185        PHP_RSHUTDOWN(pcntl),
00186        PHP_MINFO(pcntl),
00187        NO_VERSION_YET,
00188        PHP_MODULE_GLOBALS(pcntl),
00189        PHP_GINIT(pcntl),
00190        NULL,
00191        NULL,
00192        STANDARD_MODULE_PROPERTIES_EX
00193 };
00194 
00195 #ifdef COMPILE_DL_PCNTL
00196 ZEND_GET_MODULE(pcntl)
00197 #endif
00198 
00199 static void pcntl_signal_handler(int);
00200 static void pcntl_signal_dispatch();
00201   
00202 void php_register_signal_constants(INIT_FUNC_ARGS)
00203 {
00204 
00205        /* Wait Constants */
00206 #ifdef WNOHANG
00207        REGISTER_LONG_CONSTANT("WNOHANG",  (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
00208 #endif
00209 #ifdef WUNTRACED
00210        REGISTER_LONG_CONSTANT("WUNTRACED",  (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
00211 #endif
00212 
00213        /* Signal Constants */
00214        REGISTER_LONG_CONSTANT("SIG_IGN",  (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
00215        REGISTER_LONG_CONSTANT("SIG_DFL",  (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
00216        REGISTER_LONG_CONSTANT("SIG_ERR",  (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
00217        REGISTER_LONG_CONSTANT("SIGHUP",   (long) SIGHUP,  CONST_CS | CONST_PERSISTENT);
00218        REGISTER_LONG_CONSTANT("SIGINT",   (long) SIGINT,  CONST_CS | CONST_PERSISTENT);
00219        REGISTER_LONG_CONSTANT("SIGQUIT",  (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
00220        REGISTER_LONG_CONSTANT("SIGILL",   (long) SIGILL,  CONST_CS | CONST_PERSISTENT);
00221        REGISTER_LONG_CONSTANT("SIGTRAP",  (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
00222        REGISTER_LONG_CONSTANT("SIGABRT",  (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
00223 #ifdef SIGIOT
00224        REGISTER_LONG_CONSTANT("SIGIOT",   (long) SIGIOT,  CONST_CS | CONST_PERSISTENT);
00225 #endif
00226        REGISTER_LONG_CONSTANT("SIGBUS",   (long) SIGBUS,  CONST_CS | CONST_PERSISTENT);
00227        REGISTER_LONG_CONSTANT("SIGFPE",   (long) SIGFPE,  CONST_CS | CONST_PERSISTENT);
00228        REGISTER_LONG_CONSTANT("SIGKILL",  (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
00229        REGISTER_LONG_CONSTANT("SIGUSR1",  (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
00230        REGISTER_LONG_CONSTANT("SIGSEGV",  (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
00231        REGISTER_LONG_CONSTANT("SIGUSR2",  (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
00232        REGISTER_LONG_CONSTANT("SIGPIPE",  (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
00233        REGISTER_LONG_CONSTANT("SIGALRM",  (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
00234        REGISTER_LONG_CONSTANT("SIGTERM",  (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
00235 #ifdef SIGSTKFLT
00236        REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
00237 #endif 
00238 #ifdef SIGCLD
00239        REGISTER_LONG_CONSTANT("SIGCLD",   (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
00240 #endif
00241 #ifdef SIGCHLD
00242        REGISTER_LONG_CONSTANT("SIGCHLD",  (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
00243 #endif
00244        REGISTER_LONG_CONSTANT("SIGCONT",  (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
00245        REGISTER_LONG_CONSTANT("SIGSTOP",  (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
00246        REGISTER_LONG_CONSTANT("SIGTSTP",  (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
00247        REGISTER_LONG_CONSTANT("SIGTTIN",  (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
00248        REGISTER_LONG_CONSTANT("SIGTTOU",  (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
00249        REGISTER_LONG_CONSTANT("SIGURG",   (long) SIGURG , CONST_CS | CONST_PERSISTENT);
00250        REGISTER_LONG_CONSTANT("SIGXCPU",  (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
00251        REGISTER_LONG_CONSTANT("SIGXFSZ",  (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
00252        REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
00253        REGISTER_LONG_CONSTANT("SIGPROF",  (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
00254        REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
00255 #ifdef SIGPOLL
00256        REGISTER_LONG_CONSTANT("SIGPOLL",  (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
00257 #endif
00258        REGISTER_LONG_CONSTANT("SIGIO",    (long) SIGIO, CONST_CS | CONST_PERSISTENT);
00259 #ifdef SIGPWR
00260        REGISTER_LONG_CONSTANT("SIGPWR",   (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
00261 #endif
00262 #ifdef SIGSYS
00263        REGISTER_LONG_CONSTANT("SIGSYS",   (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
00264        REGISTER_LONG_CONSTANT("SIGBABY",  (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
00265 #endif
00266 
00267 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
00268        REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
00269        REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
00270        REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
00271 #endif
00272 
00273        /* {{{ "how" argument for sigprocmask */
00274 #ifdef HAVE_SIGPROCMASK
00275        REGISTER_LONG_CONSTANT("SIG_BLOCK",   SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
00276        REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT);
00277        REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT);
00278 #endif
00279        /* }}} */
00280 
00281        /* {{{ si_code */
00282 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
00283        REGISTER_LONG_CONSTANT("SI_USER",    SI_USER,    CONST_CS | CONST_PERSISTENT);
00284 #ifdef SI_NOINFO
00285        REGISTER_LONG_CONSTANT("SI_NOINFO",  SI_NOINFO,  CONST_CS | CONST_PERSISTENT);
00286 #endif
00287 #ifdef SI_KERNEL
00288        REGISTER_LONG_CONSTANT("SI_KERNEL",  SI_KERNEL,  CONST_CS | CONST_PERSISTENT);
00289 #endif
00290        REGISTER_LONG_CONSTANT("SI_QUEUE",   SI_QUEUE,   CONST_CS | CONST_PERSISTENT);
00291        REGISTER_LONG_CONSTANT("SI_TIMER",   SI_TIMER,   CONST_CS | CONST_PERSISTENT);
00292        REGISTER_LONG_CONSTANT("SI_MESGQ",   SI_MESGQ,   CONST_CS | CONST_PERSISTENT);
00293        REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
00294 #ifdef SI_SIGIO
00295        REGISTER_LONG_CONSTANT("SI_SIGIO",   SI_SIGIO,   CONST_CS | CONST_PERSISTENT);
00296 #endif
00297 #ifdef SI_TKILL
00298        REGISTER_LONG_CONSTANT("SI_TKILL",   SI_TKILL,   CONST_CS | CONST_PERSISTENT);
00299 #endif
00300 
00301        /* si_code for SIGCHILD */
00302 #ifdef CLD_EXITED
00303        REGISTER_LONG_CONSTANT("CLD_EXITED",    CLD_EXITED,    CONST_CS | CONST_PERSISTENT);
00304 #endif
00305 #ifdef CLD_KILLED
00306        REGISTER_LONG_CONSTANT("CLD_KILLED",    CLD_KILLED,    CONST_CS | CONST_PERSISTENT);
00307 #endif
00308 #ifdef CLD_DUMPED
00309        REGISTER_LONG_CONSTANT("CLD_DUMPED",    CLD_DUMPED,    CONST_CS | CONST_PERSISTENT);
00310 #endif
00311 #ifdef CLD_TRAPPED
00312        REGISTER_LONG_CONSTANT("CLD_TRAPPED",   CLD_TRAPPED,   CONST_CS | CONST_PERSISTENT);
00313 #endif
00314 #ifdef CLD_STOPPED
00315        REGISTER_LONG_CONSTANT("CLD_STOPPED",   CLD_STOPPED,   CONST_CS | CONST_PERSISTENT);
00316 #endif
00317 #ifdef CLD_CONTINUED
00318        REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
00319 #endif
00320 
00321        /* si_code for SIGTRAP */
00322 #ifdef TRAP_BRKPT
00323        REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
00324 #endif
00325 #ifdef TRAP_TRACE
00326        REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
00327 #endif
00328 
00329        /* si_code for SIGPOLL */
00330 #ifdef POLL_IN
00331        REGISTER_LONG_CONSTANT("POLL_IN",  POLL_IN,  CONST_CS | CONST_PERSISTENT);
00332 #endif
00333 #ifdef POLL_OUT
00334        REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
00335 #endif
00336 #ifdef POLL_MSG
00337        REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
00338 #endif
00339 #ifdef POLL_ERR
00340        REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
00341 #endif
00342 #ifdef POLL_PRI
00343        REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
00344 #endif
00345 #ifdef POLL_HUP
00346        REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
00347 #endif
00348 
00349 #ifdef ILL_ILLOPC
00350        REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
00351 #endif
00352 #ifdef ILL_ILLOPN
00353        REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
00354 #endif
00355 #ifdef ILL_ILLADR
00356        REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
00357 #endif
00358 #ifdef ILL_ILLTRP
00359        REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
00360 #endif
00361 #ifdef ILL_PRVOPC
00362        REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
00363 #endif
00364 #ifdef ILL_PRVREG
00365        REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
00366 #endif
00367 #ifdef ILL_COPROC
00368        REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
00369 #endif
00370 #ifdef ILL_BADSTK
00371        REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
00372 #endif
00373 
00374 #ifdef FPE_INTDIV
00375        REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
00376 #endif
00377 #ifdef FPE_INTOVF
00378        REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
00379 #endif
00380 #ifdef FPE_FLTDIV
00381        REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
00382 #endif
00383 #ifdef FPE_FLTOVF
00384        REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
00385 #endif
00386 #ifdef FPE_FLTUND
00387        REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
00388 #endif
00389 #ifdef FPE_FLTRES
00390        REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
00391 #endif
00392 #ifdef FPE_FLTINV
00393        REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
00394 #endif
00395 #ifdef FPE_FLTSUB
00396        REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
00397 #endif
00398 
00399 #ifdef SEGV_MAPERR
00400        REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
00401 #endif
00402 #ifdef SEGV_ACCERR
00403        REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
00404 #endif
00405 
00406 #ifdef BUS_ADRALN
00407        REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
00408 #endif
00409 #ifdef BUS_ADRERR
00410        REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
00411 #endif
00412 #ifdef BUS_OBJERR
00413        REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
00414 #endif
00415 #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */
00416        /* }}} */
00417 }
00418 
00419 static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
00420 {
00421 #ifdef EINTR
00422        REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
00423 #endif
00424 #ifdef ECHILD
00425        REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
00426 #endif
00427 #ifdef EINVAL
00428        REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
00429 #endif
00430 #ifdef EAGAIN
00431        REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
00432 #endif
00433 #ifdef ESRCH
00434        REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
00435 #endif
00436 #ifdef EACCES
00437        REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
00438 #endif
00439 #ifdef EPERM
00440        REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
00441 #endif
00442 #ifdef ENOMEM
00443        REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
00444 #endif
00445 #ifdef E2BIG
00446        REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
00447 #endif
00448 #ifdef EFAULT
00449        REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
00450 #endif
00451 #ifdef EIO
00452        REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
00453 #endif
00454 #ifdef EISDIR
00455        REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
00456 #endif
00457 #ifdef ELIBBAD
00458        REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
00459 #endif
00460 #ifdef ELOOP
00461        REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
00462 #endif
00463 #ifdef EMFILE
00464        REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
00465 #endif
00466 #ifdef ENAMETOOLONG
00467        REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
00468 #endif
00469 #ifdef ENFILE
00470        REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
00471 #endif
00472 #ifdef ENOENT
00473        REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
00474 #endif
00475 #ifdef ENOEXEC
00476        REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
00477 #endif
00478 #ifdef ENOTDIR
00479        REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
00480 #endif
00481 #ifdef ETXTBSY
00482        REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
00483 #endif
00484 }
00485 
00486 static PHP_GINIT_FUNCTION(pcntl)
00487 { 
00488        memset(pcntl_globals, 0, sizeof(*pcntl_globals));
00489 }
00490 
00491 PHP_RINIT_FUNCTION(pcntl)
00492 {
00493        zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
00494        PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
00495        return SUCCESS;
00496 }
00497 
00498 PHP_MINIT_FUNCTION(pcntl)
00499 {
00500        php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
00501        php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
00502        php_add_tick_function(pcntl_signal_dispatch);
00503 
00504        return SUCCESS;
00505 }
00506 
00507 PHP_MSHUTDOWN_FUNCTION(pcntl)
00508 {
00509        return SUCCESS;
00510 }
00511 
00512 PHP_RSHUTDOWN_FUNCTION(pcntl)
00513 {
00514        struct php_pcntl_pending_signal *sig;
00515 
00516        /* FIXME: if a signal is delivered after this point, things will go pear shaped;
00517         * need to remove signal handlers */
00518        zend_hash_destroy(&PCNTL_G(php_signal_table));
00519        while (PCNTL_G(head)) {
00520               sig = PCNTL_G(head);
00521               PCNTL_G(head) = sig->next;
00522               efree(sig);
00523        }
00524        while (PCNTL_G(spares)) {
00525               sig = PCNTL_G(spares);
00526               PCNTL_G(spares) = sig->next;
00527               efree(sig);
00528        }
00529        return SUCCESS;
00530 }
00531 
00532 PHP_MINFO_FUNCTION(pcntl)
00533 {
00534        php_info_print_table_start();
00535        php_info_print_table_header(2, "pcntl support", "enabled");
00536        php_info_print_table_end();
00537 }
00538 
00539 /* {{{ proto int pcntl_fork(void)
00540    Forks the currently running process following the same behavior as the UNIX fork() system call*/
00541 PHP_FUNCTION(pcntl_fork)
00542 {
00543        pid_t id;
00544 
00545        id = fork();
00546        if (id == -1) {
00547               PCNTL_G(last_error) = errno;
00548               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
00549        }
00550        
00551        RETURN_LONG((long) id);
00552 }
00553 /* }}} */
00554 
00555 /* {{{ proto int pcntl_alarm(int seconds)
00556    Set an alarm clock for delivery of a signal*/
00557 PHP_FUNCTION(pcntl_alarm)
00558 {
00559        long seconds;
00560 
00561        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
00562               return;
00563        
00564        RETURN_LONG ((long) alarm(seconds));
00565 }
00566 /* }}} */
00567 
00568 /* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
00569    Waits on or returns the status of a forked child as defined by the waitpid() system call */
00570 PHP_FUNCTION(pcntl_waitpid)
00571 {
00572        long pid, options = 0;
00573        zval *z_status = NULL;
00574        int status;
00575        pid_t child_id;
00576 
00577        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
00578               return;
00579        
00580        convert_to_long_ex(&z_status);
00581 
00582        status = Z_LVAL_P(z_status);
00583 
00584        child_id = waitpid((pid_t) pid, &status, options);
00585 
00586        if (child_id < 0) {
00587               PCNTL_G(last_error) = errno;
00588        }
00589 
00590        Z_LVAL_P(z_status) = status;
00591 
00592        RETURN_LONG((long) child_id);
00593 }
00594 /* }}} */
00595 
00596 /* {{{ proto int pcntl_wait(int &status)
00597    Waits on or returns the status of a forked child as defined by the waitpid() system call */
00598 PHP_FUNCTION(pcntl_wait)
00599 {
00600        long options = 0;
00601        zval *z_status = NULL;
00602        int status;
00603        pid_t child_id;
00604 
00605        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
00606               return;
00607        
00608        convert_to_long_ex(&z_status);
00609 
00610        status = Z_LVAL_P(z_status);
00611 #ifdef HAVE_WAIT3
00612        if(options) {
00613               child_id = wait3(&status, options, NULL);
00614        }
00615        else {
00616               child_id = wait(&status);
00617        }
00618 #else
00619        child_id = wait(&status);
00620 #endif
00621        if (child_id < 0) {
00622               PCNTL_G(last_error) = errno;
00623        }
00624 
00625        Z_LVAL_P(z_status) = status;
00626 
00627        RETURN_LONG((long) child_id);
00628 }
00629 /* }}} */
00630 
00631 /* {{{ proto bool pcntl_wifexited(int status) 
00632    Returns true if the child status code represents a successful exit */
00633 PHP_FUNCTION(pcntl_wifexited)
00634 {
00635 #ifdef WIFEXITED
00636        long status_word;
00637 
00638        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00639               return;
00640        }
00641 
00642        if (WIFEXITED(status_word))
00643               RETURN_TRUE;
00644 #endif
00645        RETURN_FALSE;
00646 }
00647 /* }}} */
00648 
00649 /* {{{ proto bool pcntl_wifstopped(int status) 
00650    Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
00651 PHP_FUNCTION(pcntl_wifstopped)
00652 {
00653 #ifdef WIFSTOPPED
00654        long status_word;
00655 
00656        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00657               return;
00658        }
00659 
00660        if (WIFSTOPPED(status_word))
00661               RETURN_TRUE;
00662 #endif
00663        RETURN_FALSE;
00664 }
00665 /* }}} */
00666 
00667 /* {{{ proto bool pcntl_wifsignaled(int status) 
00668    Returns true if the child status code represents a process that was terminated due to a signal */
00669 PHP_FUNCTION(pcntl_wifsignaled)
00670 {
00671 #ifdef WIFSIGNALED
00672        long status_word;
00673 
00674        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00675               return;
00676        }
00677 
00678        if (WIFSIGNALED(status_word))
00679               RETURN_TRUE;
00680 #endif
00681        RETURN_FALSE;
00682 }
00683 /* }}} */
00684 
00685 /* {{{ proto int pcntl_wexitstatus(int status) 
00686    Returns the status code of a child's exit */
00687 PHP_FUNCTION(pcntl_wexitstatus)
00688 {
00689 #ifdef WEXITSTATUS
00690        long status_word;
00691 
00692        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00693               return;
00694        }
00695 
00696        RETURN_LONG(WEXITSTATUS(status_word));
00697 #else
00698        RETURN_FALSE;
00699 #endif
00700 }
00701 /* }}} */
00702 
00703 /* {{{ proto int pcntl_wtermsig(int status) 
00704    Returns the number of the signal that terminated the process who's status code is passed  */
00705 PHP_FUNCTION(pcntl_wtermsig)
00706 {
00707 #ifdef WTERMSIG
00708        long status_word;
00709 
00710        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00711               return;
00712        }
00713 
00714        RETURN_LONG(WTERMSIG(status_word));
00715 #else
00716        RETURN_FALSE;
00717 #endif
00718 }
00719 /* }}} */
00720 
00721 /* {{{ proto int pcntl_wstopsig(int status) 
00722    Returns the number of the signal that caused the process to stop who's status code is passed */
00723 PHP_FUNCTION(pcntl_wstopsig)
00724 {
00725 #ifdef WSTOPSIG
00726        long status_word;
00727 
00728        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
00729               return;
00730        }
00731 
00732        RETURN_LONG(WSTOPSIG(status_word));
00733 #else
00734        RETURN_FALSE;
00735 #endif
00736 }
00737 /* }}} */
00738 
00739 /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
00740    Executes specified program in current process space as defined by exec(2) */
00741 PHP_FUNCTION(pcntl_exec)
00742 {
00743        zval *args = NULL, *envs = NULL;
00744        zval **element;
00745        HashTable *args_hash, *envs_hash;
00746        int argc = 0, argi = 0;
00747        int envc = 0, envi = 0;
00748        int return_val = 0;
00749        char **argv = NULL, **envp = NULL;
00750        char **current_arg, **pair;
00751        int pair_length;
00752        char *key;
00753        uint key_length;
00754        char *path;
00755        int path_len;
00756        ulong key_num;
00757               
00758        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) {
00759               return;
00760        }
00761        
00762        if (ZEND_NUM_ARGS() > 1) {
00763               /* Build argumnent list */
00764               args_hash = HASH_OF(args);
00765               argc = zend_hash_num_elements(args_hash);
00766               
00767               argv = safe_emalloc((argc + 2), sizeof(char *), 0);
00768               *argv = path;
00769               for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1; 
00770                      (argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
00771                      (argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
00772 
00773                      convert_to_string_ex(element);
00774                      *current_arg = Z_STRVAL_PP(element);
00775               }
00776               *(current_arg) = NULL;
00777        } else {
00778               argv = emalloc(2 * sizeof(char *));
00779               *argv = path;
00780               *(argv+1) = NULL;
00781        }
00782 
00783        if ( ZEND_NUM_ARGS() == 3 ) {
00784               /* Build environment pair list */
00785               envs_hash = HASH_OF(envs);
00786               envc = zend_hash_num_elements(envs_hash);
00787               
00788               envp = safe_emalloc((envc + 1), sizeof(char *), 0);
00789               for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp; 
00790                      (envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
00791                      (envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
00792                      switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
00793                             case HASH_KEY_IS_LONG:
00794                                    key = emalloc(101);
00795                                    snprintf(key, 100, "%ld", key_num);
00796                                    key_length = strlen(key);
00797                                    break;
00798                             case HASH_KEY_NON_EXISTANT:
00799                                    pair--;
00800                                    continue;
00801                      }
00802 
00803                      convert_to_string_ex(element);
00804 
00805                      /* Length of element + equal sign + length of key + null */ 
00806                      pair_length = Z_STRLEN_PP(element) + key_length + 2;
00807                      *pair = emalloc(pair_length);
00808                      strlcpy(*pair, key, key_length); 
00809                      strlcat(*pair, "=", pair_length);
00810                      strlcat(*pair, Z_STRVAL_PP(element), pair_length);
00811                      
00812                      /* Cleanup */
00813                      if (return_val == HASH_KEY_IS_LONG) efree(key);
00814               }
00815               *(pair) = NULL;
00816 
00817               if (execve(path, argv, envp) == -1) {
00818                      PCNTL_G(last_error) = errno;
00819                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
00820               }
00821        
00822               /* Cleanup */
00823               for (pair = envp; *pair != NULL; pair++) efree(*pair);
00824               efree(envp);
00825        } else {
00826 
00827               if (execv(path, argv) == -1) {
00828                      PCNTL_G(last_error) = errno;
00829                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
00830               }
00831        }
00832 
00833        efree(argv);
00834        
00835        RETURN_FALSE;
00836 }
00837 /* }}} */
00838 
00839 /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
00840    Assigns a system signal handler to a PHP function */
00841 PHP_FUNCTION(pcntl_signal)
00842 {
00843        zval *handle, **dest_handle = NULL;
00844        char *func_name;
00845        long signo;
00846        zend_bool restart_syscalls = 1;
00847 
00848        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
00849               return;
00850        }
00851 
00852        if (!PCNTL_G(spares)) {
00853               /* since calling malloc() from within a signal handler is not portable,
00854                * pre-allocate a few records for recording signals */
00855               int i;
00856               for (i = 0; i < 32; i++) {
00857                      struct php_pcntl_pending_signal *psig;
00858 
00859                      psig = emalloc(sizeof(*psig));
00860                      psig->next = PCNTL_G(spares);
00861                      PCNTL_G(spares) = psig;
00862               }
00863        }
00864 
00865        /* Special long value case for SIG_DFL and SIG_IGN */
00866        if (Z_TYPE_P(handle)==IS_LONG) {
00867               if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
00868                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
00869               }
00870               if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
00871                      PCNTL_G(last_error) = errno;
00872                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
00873                      RETURN_FALSE;
00874               }
00875               RETURN_TRUE;
00876        }
00877        
00878        if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
00879               PCNTL_G(last_error) = EINVAL;
00880               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
00881               efree(func_name);
00882               RETURN_FALSE;
00883        }
00884        efree(func_name);
00885        
00886        /* Add the function name to our signal table */
00887        zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
00888        if (dest_handle) zval_add_ref(dest_handle);
00889        
00890        if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
00891               PCNTL_G(last_error) = errno;
00892               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
00893               RETURN_FALSE;
00894        }
00895        RETURN_TRUE;
00896 }
00897 /* }}} */
00898 
00899 /* {{{ proto bool pcntl_signal_dispatch()
00900    Dispatch signals to signal handlers */
00901 PHP_FUNCTION(pcntl_signal_dispatch)
00902 {
00903        pcntl_signal_dispatch();
00904        RETURN_TRUE;
00905 }
00906 /* }}} */
00907 
00908 #ifdef HAVE_SIGPROCMASK
00909 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
00910    Examine and change blocked signals */
00911 PHP_FUNCTION(pcntl_sigprocmask)
00912 {
00913        long          how, signo;
00914        zval         *user_set, *user_oldset = NULL, **user_signo;
00915        sigset_t      set, oldset;
00916        HashPosition  pos;
00917 
00918        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la|z", &how, &user_set, &user_oldset) == FAILURE) {
00919               return;
00920        }
00921 
00922        if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
00923               PCNTL_G(last_error) = errno;
00924               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
00925               RETURN_FALSE;
00926        }
00927 
00928        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
00929        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
00930        {
00931               if (Z_TYPE_PP(user_signo) != IS_LONG) {
00932                      SEPARATE_ZVAL(user_signo);
00933                      convert_to_long_ex(user_signo);
00934               }
00935               signo = Z_LVAL_PP(user_signo);
00936               if (sigaddset(&set, signo) != 0) {
00937                      PCNTL_G(last_error) = errno;
00938                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
00939                      RETURN_FALSE;
00940               }
00941               zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
00942        }
00943 
00944        if (sigprocmask(how, &set, &oldset) != 0) {
00945               PCNTL_G(last_error) = errno;
00946               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
00947               RETURN_FALSE;
00948        }
00949 
00950        if (user_oldset != NULL) {
00951               if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
00952                      zval_dtor(user_oldset);
00953                      array_init(user_oldset);
00954               } else {
00955                      zend_hash_clean(Z_ARRVAL_P(user_oldset));
00956               }
00957               for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) {
00958                      if (sigismember(&oldset, signo) != 1) {
00959                             continue;
00960                      }
00961                      add_next_index_long(user_oldset, signo);
00962               }
00963        }
00964 
00965        RETURN_TRUE;
00966 }
00967 /* }}} */
00968 #endif
00969 
00970 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
00971 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
00972 {
00973        zval            *user_set, **user_signo, *user_siginfo = NULL;
00974        long             tv_sec = 0, tv_nsec = 0;
00975        sigset_t         set;
00976        HashPosition     pos;
00977        int              signo;
00978        siginfo_t        siginfo;
00979        struct timespec  timeout;
00980 
00981        if (timedwait) {
00982               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
00983                      return;
00984               }
00985        } else {
00986               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) {
00987                      return;
00988               }
00989        }
00990 
00991        if (sigemptyset(&set) != 0) {
00992               PCNTL_G(last_error) = errno;
00993               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
00994               RETURN_FALSE;
00995        }
00996 
00997        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
00998        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
00999        {
01000               if (Z_TYPE_PP(user_signo) != IS_LONG) {
01001                      SEPARATE_ZVAL(user_signo);
01002                      convert_to_long_ex(user_signo);
01003               }
01004               signo = Z_LVAL_PP(user_signo);
01005               if (sigaddset(&set, signo) != 0) {
01006                      PCNTL_G(last_error) = errno;
01007                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
01008                      RETURN_FALSE;
01009               }
01010               zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
01011        }
01012 
01013        if (timedwait) {
01014               timeout.tv_sec  = (time_t) tv_sec;
01015               timeout.tv_nsec = tv_nsec;
01016               signo = sigtimedwait(&set, &siginfo, &timeout);
01017        } else {
01018               signo = sigwaitinfo(&set, &siginfo);
01019        }
01020        if (signo == -1 && errno != EAGAIN) {
01021               PCNTL_G(last_error) = errno;
01022               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
01023        }
01024 
01025        /*
01026         * sigtimedwait and sigwaitinfo can return 0 on success on some 
01027         * platforms, e.g. NetBSD
01028         */
01029        if (!signo && siginfo.si_signo) {
01030               signo = siginfo.si_signo;
01031        }
01032 
01033        if (signo > 0 && user_siginfo) {
01034               if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
01035                      zval_dtor(user_siginfo);
01036                      array_init(user_siginfo);
01037               } else {
01038                      zend_hash_clean(Z_ARRVAL_P(user_siginfo));
01039               }
01040               add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo);
01041               add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno);
01042               add_assoc_long_ex(user_siginfo, "code",  sizeof("code"),  siginfo.si_code);
01043               switch(signo) {
01044 #ifdef SIGCHLD
01045                      case SIGCHLD:
01046                             add_assoc_long_ex(user_siginfo,   "status", sizeof("status"), siginfo.si_status);
01047 # ifdef si_utime
01048                             add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime"),  siginfo.si_utime);
01049 # endif
01050 # ifdef si_stime
01051                             add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime"),  siginfo.si_stime);
01052 # endif
01053                             add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid"),    siginfo.si_pid);
01054                             add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid"),    siginfo.si_uid);
01055                             break;
01056 #endif
01057                      case SIGILL:
01058                      case SIGFPE:
01059                      case SIGSEGV:
01060                      case SIGBUS:
01061                             add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr);
01062                             break;
01063 #ifdef SIGPOLL
01064                      case SIGPOLL:
01065                             add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band);
01066 # ifdef si_fd
01067                             add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd"),   siginfo.si_fd);
01068 # endif
01069                             break;
01070 #endif
01071                      EMPTY_SWITCH_DEFAULT_CASE();
01072               }
01073        }
01074        
01075        RETURN_LONG(signo);
01076 }
01077 /* }}} */
01078 
01079 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
01080    Synchronously wait for queued signals */
01081 PHP_FUNCTION(pcntl_sigwaitinfo)
01082 {
01083        pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
01084 }
01085 /* }}} */
01086 
01087 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
01088    Wait for queued signals */
01089 PHP_FUNCTION(pcntl_sigtimedwait)
01090 {
01091        pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
01092 }
01093 /* }}} */
01094 #endif
01095 
01096 #ifdef HAVE_GETPRIORITY
01097 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
01098    Get the priority of any process */
01099 PHP_FUNCTION(pcntl_getpriority)
01100 {
01101        long who = PRIO_PROCESS;
01102        long pid = getpid();
01103        int pri;
01104        
01105        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
01106               RETURN_FALSE;
01107        }
01108 
01109        /* needs to be cleared, since any returned value is valid */ 
01110        errno = 0;
01111 
01112        pri = getpriority(who, pid);
01113 
01114        if (errno) {
01115               PCNTL_G(last_error) = errno;
01116               switch (errno) {
01117                      case ESRCH:
01118                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
01119                             break;
01120                      case EINVAL:
01121                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
01122                             break;
01123                      default:
01124                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
01125                             break;
01126               }
01127               RETURN_FALSE;
01128        }
01129 
01130        RETURN_LONG(pri);
01131 }
01132 /* }}} */
01133 #endif
01134 
01135 #ifdef HAVE_SETPRIORITY
01136 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
01137    Change the priority of any process */
01138 PHP_FUNCTION(pcntl_setpriority)
01139 {
01140        long who = PRIO_PROCESS;
01141        long pid = getpid();
01142        long pri;
01143 
01144        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
01145               RETURN_FALSE;
01146        }
01147 
01148        if (setpriority(who, pid, pri)) {
01149               PCNTL_G(last_error) = errno;
01150               switch (errno) {
01151                      case ESRCH:
01152                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
01153                             break;
01154                      case EINVAL:
01155                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
01156                             break;
01157                      case EPERM:
01158                             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);
01159                             break;
01160                      case EACCES:
01161                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
01162                             break;
01163                      default:
01164                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
01165                             break;
01166               }
01167               RETURN_FALSE;
01168        }
01169        
01170        RETURN_TRUE;
01171 }
01172 /* }}} */
01173 #endif
01174 
01175 /* {{{ proto int pcntl_get_last_error(void)
01176    Retrieve the error number set by the last pcntl function which failed. */
01177 PHP_FUNCTION(pcntl_get_last_error)
01178 {
01179         RETURN_LONG(PCNTL_G(last_error));
01180 }
01181 /* }}} */
01182 
01183 /* {{{ proto string pcntl_strerror(int errno)
01184    Retrieve the system error message associated with the given errno. */
01185 PHP_FUNCTION(pcntl_strerror)
01186 {
01187         long error;
01188 
01189         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
01190                 RETURN_FALSE;
01191         }
01192 
01193         RETURN_STRING(strerror(error), 1);
01194 }
01195 /* }}} */
01196 
01197 /* Our custom signal handler that calls the appropriate php_function */
01198 static void pcntl_signal_handler(int signo)
01199 {
01200        struct php_pcntl_pending_signal *psig;
01201        TSRMLS_FETCH();
01202        
01203        psig = PCNTL_G(spares);
01204        if (!psig) {
01205               /* oops, too many signals for us to track, so we'll forget about this one */
01206               return;
01207        }
01208        PCNTL_G(spares) = psig->next;
01209 
01210        psig->signo = signo;
01211        psig->next = NULL;
01212 
01213        /* the head check is important, as the tick handler cannot atomically clear both
01214         * the head and tail */
01215        if (PCNTL_G(head) && PCNTL_G(tail)) {
01216               PCNTL_G(tail)->next = psig;
01217        } else {
01218               PCNTL_G(head) = psig;
01219        }
01220        PCNTL_G(tail) = psig;
01221 }
01222 
01223 void pcntl_signal_dispatch()
01224 {
01225        zval *param, **handle, *retval;
01226        struct php_pcntl_pending_signal *queue, *next;
01227        sigset_t mask;
01228        sigset_t old_mask;
01229        TSRMLS_FETCH();
01230               
01231        /* Mask all signals */
01232        sigfillset(&mask);
01233        sigprocmask(SIG_BLOCK, &mask, &old_mask);
01234 
01235        /* Bail if the queue is empty or if we are already playing the queue*/
01236        if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
01237               sigprocmask(SIG_SETMASK, &old_mask, NULL);
01238               return;
01239        }
01240 
01241        /* Prevent reentrant handler calls */
01242        PCNTL_G(processing_signal_queue) = 1;
01243 
01244        queue = PCNTL_G(head);
01245        PCNTL_G(head) = NULL; /* simple stores are atomic */
01246        
01247        /* Allocate */
01248 
01249        while (queue) {
01250               if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
01251                      MAKE_STD_ZVAL(retval);
01252                      MAKE_STD_ZVAL(param);
01253                      ZVAL_NULL(retval);
01254                      ZVAL_LONG(param, queue->signo);
01255 
01256                      /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
01257                      /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
01258                      call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
01259                      zval_ptr_dtor(&param);
01260                      zval_ptr_dtor(&retval);
01261               }
01262 
01263               next = queue->next;
01264               queue->next = PCNTL_G(spares);
01265               PCNTL_G(spares) = queue;
01266               queue = next;
01267        }
01268 
01269        /* Re-enable queue */
01270        PCNTL_G(processing_signal_queue) = 0;
01271        
01272        /* return signal mask to previous state */
01273        sigprocmask(SIG_SETMASK, &old_mask, NULL);
01274 }
01275 
01276 
01277 
01278 /*
01279  * Local variables:
01280  * tab-width: 4
01281  * c-basic-offset: 4
01282  * indent-tabs-mode: t
01283  * End:
01284  */