root/ext/pcntl/pcntl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. php_pcntl_register_errno_constants
  3. PHP_GINIT_FUNCTION
  4. PHP_RINIT_FUNCTION
  5. PHP_MINIT_FUNCTION
  6. PHP_MSHUTDOWN_FUNCTION
  7. PHP_RSHUTDOWN_FUNCTION
  8. PHP_MINFO_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. pcntl_sigwaitinfo
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. pcntl_signal_handler
  31. pcntl_signal_dispatch

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Jason Greene <jason@inetgurus.net>                           |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 /* $Id$ */
  20 
  21 #define PCNTL_DEBUG 0
  22 
  23 #if PCNTL_DEBUG
  24 #define DEBUG_OUT printf("DEBUG: ");printf
  25 #define IF_DEBUG(z) z
  26 #else
  27 #define IF_DEBUG(z)
  28 #endif
  29 
  30 #ifdef HAVE_CONFIG_H
  31 #include "config.h"
  32 #endif
  33 
  34 #include "php.h"
  35 #include "php_ini.h"
  36 #include "ext/standard/info.h"
  37 #include "php_pcntl.h"
  38 #include "php_signal.h"
  39 #include "php_ticks.h"
  40 
  41 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
  42 #include <sys/wait.h>
  43 #include <sys/time.h>
  44 #include <sys/resource.h>
  45 #endif
  46 
  47 #include <errno.h>
  48 
  49 ZEND_DECLARE_MODULE_GLOBALS(pcntl)
  50 static PHP_GINIT_FUNCTION(pcntl);
  51 
  52 /* {{{ arginfo */
  53 ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0)
  54 ZEND_END_ARG_INFO()
  55 
  56 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
  57         ZEND_ARG_INFO(0, pid)
  58         ZEND_ARG_INFO(1, status)
  59         ZEND_ARG_INFO(0, options)
  60 ZEND_END_ARG_INFO()
  61 
  62 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
  63         ZEND_ARG_INFO(1, status)
  64         ZEND_ARG_INFO(0, options)
  65 ZEND_END_ARG_INFO()
  66 
  67 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
  68         ZEND_ARG_INFO(0, signo)
  69         ZEND_ARG_INFO(0, handler)
  70         ZEND_ARG_INFO(0, restart_syscalls)
  71 ZEND_END_ARG_INFO()
  72 
  73 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
  74         ZEND_ARG_INFO(0, how)
  75         ZEND_ARG_INFO(0, set)
  76         ZEND_ARG_INFO(1, oldset)
  77 ZEND_END_ARG_INFO()
  78 
  79 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
  80         ZEND_ARG_INFO(0, set)
  81         ZEND_ARG_INFO(1, info)
  82 ZEND_END_ARG_INFO()
  83 
  84 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
  85         ZEND_ARG_INFO(0, set)
  86         ZEND_ARG_INFO(1, info)
  87         ZEND_ARG_INFO(0, seconds)
  88         ZEND_ARG_INFO(0, nanoseconds)
  89 ZEND_END_ARG_INFO()
  90 
  91 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
  92         ZEND_ARG_INFO(0, status)
  93 ZEND_END_ARG_INFO()
  94 
  95 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1)
  96         ZEND_ARG_INFO(0, status)
  97 ZEND_END_ARG_INFO()
  98 
  99 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1)
 100         ZEND_ARG_INFO(0, status)
 101 ZEND_END_ARG_INFO()
 102 
 103 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1)
 104         ZEND_ARG_INFO(0, status)
 105 ZEND_END_ARG_INFO()
 106 
 107 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1)
 108         ZEND_ARG_INFO(0, status)
 109 ZEND_END_ARG_INFO()
 110 
 111 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1)
 112         ZEND_ARG_INFO(0, status)
 113 ZEND_END_ARG_INFO()
 114 
 115 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1)
 116         ZEND_ARG_INFO(0, path)
 117         ZEND_ARG_INFO(0, args)
 118         ZEND_ARG_INFO(0, envs)
 119 ZEND_END_ARG_INFO()
 120 
 121 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1)
 122         ZEND_ARG_INFO(0, seconds)
 123 ZEND_END_ARG_INFO()
 124 
 125 #ifdef HAVE_GETPRIORITY
 126 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0)
 127         ZEND_ARG_INFO(0, pid)
 128         ZEND_ARG_INFO(0, process_identifier)
 129 ZEND_END_ARG_INFO()
 130 #endif
 131 
 132 #ifdef HAVE_SETPRIORITY
 133 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
 134         ZEND_ARG_INFO(0, priority)
 135         ZEND_ARG_INFO(0, pid)
 136         ZEND_ARG_INFO(0, process_identifier)
 137 ZEND_END_ARG_INFO()
 138 #endif
 139 
 140 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
 141         ZEND_ARG_INFO(0, errno)
 142 ZEND_END_ARG_INFO()
 143 /* }}} */
 144 
 145 const zend_function_entry pcntl_functions[] = {
 146         PHP_FE(pcntl_fork,                      arginfo_pcntl_void)
 147         PHP_FE(pcntl_waitpid,           arginfo_pcntl_waitpid)
 148         PHP_FE(pcntl_wait,                      arginfo_pcntl_wait)
 149         PHP_FE(pcntl_signal,            arginfo_pcntl_signal)
 150         PHP_FE(pcntl_signal_dispatch,   arginfo_pcntl_void)
 151         PHP_FE(pcntl_wifexited,         arginfo_pcntl_wifexited)
 152         PHP_FE(pcntl_wifstopped,        arginfo_pcntl_wifstopped)
 153         PHP_FE(pcntl_wifsignaled,       arginfo_pcntl_wifsignaled)
 154         PHP_FE(pcntl_wexitstatus,       arginfo_pcntl_wifexitstatus)
 155         PHP_FE(pcntl_wtermsig,          arginfo_pcntl_wtermsig)
 156         PHP_FE(pcntl_wstopsig,          arginfo_pcntl_wstopsig)
 157         PHP_FE(pcntl_exec,                      arginfo_pcntl_exec)
 158         PHP_FE(pcntl_alarm,                     arginfo_pcntl_alarm)
 159         PHP_FE(pcntl_get_last_error,    arginfo_pcntl_void)
 160         PHP_FALIAS(pcntl_errno, pcntl_get_last_error,   NULL)
 161         PHP_FE(pcntl_strerror,          arginfo_pcntl_strerror)
 162 #ifdef HAVE_GETPRIORITY
 163         PHP_FE(pcntl_getpriority,       arginfo_pcntl_getpriority)
 164 #endif
 165 #ifdef HAVE_SETPRIORITY
 166         PHP_FE(pcntl_setpriority,       arginfo_pcntl_setpriority)
 167 #endif
 168 #ifdef HAVE_SIGPROCMASK
 169         PHP_FE(pcntl_sigprocmask,       arginfo_pcntl_sigprocmask)
 170 #endif
 171 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
 172         PHP_FE(pcntl_sigwaitinfo,       arginfo_pcntl_sigwaitinfo)
 173         PHP_FE(pcntl_sigtimedwait,      arginfo_pcntl_sigtimedwait)
 174 #endif
 175         PHP_FE_END
 176 };
 177 
 178 zend_module_entry pcntl_module_entry = {
 179         STANDARD_MODULE_HEADER,
 180         "pcntl",
 181         pcntl_functions,
 182         PHP_MINIT(pcntl),
 183         PHP_MSHUTDOWN(pcntl),
 184         PHP_RINIT(pcntl),
 185         PHP_RSHUTDOWN(pcntl),
 186         PHP_MINFO(pcntl),
 187         NO_VERSION_YET,
 188         PHP_MODULE_GLOBALS(pcntl),
 189         PHP_GINIT(pcntl),
 190         NULL,
 191         NULL,
 192         STANDARD_MODULE_PROPERTIES_EX
 193 };
 194 
 195 #ifdef COMPILE_DL_PCNTL
 196 ZEND_GET_MODULE(pcntl)
 197 #endif
 198 
 199 static void pcntl_signal_handler(int);
 200 static void pcntl_signal_dispatch();
 201 
 202 void php_register_signal_constants(INIT_FUNC_ARGS)
 203 {
 204 
 205         /* Wait Constants */
 206 #ifdef WNOHANG
 207         REGISTER_LONG_CONSTANT("WNOHANG",  (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
 208 #endif
 209 #ifdef WUNTRACED
 210         REGISTER_LONG_CONSTANT("WUNTRACED",  (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
 211 #endif
 212 
 213         /* Signal Constants */
 214         REGISTER_LONG_CONSTANT("SIG_IGN",  (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
 215         REGISTER_LONG_CONSTANT("SIG_DFL",  (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
 216         REGISTER_LONG_CONSTANT("SIG_ERR",  (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
 217         REGISTER_LONG_CONSTANT("SIGHUP",   (long) SIGHUP,  CONST_CS | CONST_PERSISTENT);
 218         REGISTER_LONG_CONSTANT("SIGINT",   (long) SIGINT,  CONST_CS | CONST_PERSISTENT);
 219         REGISTER_LONG_CONSTANT("SIGQUIT",  (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
 220         REGISTER_LONG_CONSTANT("SIGILL",   (long) SIGILL,  CONST_CS | CONST_PERSISTENT);
 221         REGISTER_LONG_CONSTANT("SIGTRAP",  (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
 222         REGISTER_LONG_CONSTANT("SIGABRT",  (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
 223 #ifdef SIGIOT
 224         REGISTER_LONG_CONSTANT("SIGIOT",   (long) SIGIOT,  CONST_CS | CONST_PERSISTENT);
 225 #endif
 226         REGISTER_LONG_CONSTANT("SIGBUS",   (long) SIGBUS,  CONST_CS | CONST_PERSISTENT);
 227         REGISTER_LONG_CONSTANT("SIGFPE",   (long) SIGFPE,  CONST_CS | CONST_PERSISTENT);
 228         REGISTER_LONG_CONSTANT("SIGKILL",  (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
 229         REGISTER_LONG_CONSTANT("SIGUSR1",  (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
 230         REGISTER_LONG_CONSTANT("SIGSEGV",  (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
 231         REGISTER_LONG_CONSTANT("SIGUSR2",  (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
 232         REGISTER_LONG_CONSTANT("SIGPIPE",  (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
 233         REGISTER_LONG_CONSTANT("SIGALRM",  (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
 234         REGISTER_LONG_CONSTANT("SIGTERM",  (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
 235 #ifdef SIGSTKFLT
 236         REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
 237 #endif
 238 #ifdef SIGCLD
 239         REGISTER_LONG_CONSTANT("SIGCLD",   (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
 240 #endif
 241 #ifdef SIGCHLD
 242         REGISTER_LONG_CONSTANT("SIGCHLD",  (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
 243 #endif
 244         REGISTER_LONG_CONSTANT("SIGCONT",  (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
 245         REGISTER_LONG_CONSTANT("SIGSTOP",  (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
 246         REGISTER_LONG_CONSTANT("SIGTSTP",  (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
 247         REGISTER_LONG_CONSTANT("SIGTTIN",  (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
 248         REGISTER_LONG_CONSTANT("SIGTTOU",  (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
 249         REGISTER_LONG_CONSTANT("SIGURG",   (long) SIGURG , CONST_CS | CONST_PERSISTENT);
 250         REGISTER_LONG_CONSTANT("SIGXCPU",  (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
 251         REGISTER_LONG_CONSTANT("SIGXFSZ",  (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
 252         REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
 253         REGISTER_LONG_CONSTANT("SIGPROF",  (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
 254         REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
 255 #ifdef SIGPOLL
 256         REGISTER_LONG_CONSTANT("SIGPOLL",  (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
 257 #endif
 258         REGISTER_LONG_CONSTANT("SIGIO",    (long) SIGIO, CONST_CS | CONST_PERSISTENT);
 259 #ifdef SIGPWR
 260         REGISTER_LONG_CONSTANT("SIGPWR",   (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
 261 #endif
 262 #ifdef SIGSYS
 263         REGISTER_LONG_CONSTANT("SIGSYS",   (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
 264         REGISTER_LONG_CONSTANT("SIGBABY",  (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
 265 #endif
 266 
 267 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
 268         REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
 269         REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
 270         REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
 271 #endif
 272 
 273         /* {{{ "how" argument for sigprocmask */
 274 #ifdef HAVE_SIGPROCMASK
 275         REGISTER_LONG_CONSTANT("SIG_BLOCK",   SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
 276         REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT);
 277         REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT);
 278 #endif
 279         /* }}} */
 280 
 281         /* {{{ si_code */
 282 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
 283         REGISTER_LONG_CONSTANT("SI_USER",    SI_USER,    CONST_CS | CONST_PERSISTENT);
 284 #ifdef SI_NOINFO
 285         REGISTER_LONG_CONSTANT("SI_NOINFO",  SI_NOINFO,  CONST_CS | CONST_PERSISTENT);
 286 #endif
 287 #ifdef SI_KERNEL
 288         REGISTER_LONG_CONSTANT("SI_KERNEL",  SI_KERNEL,  CONST_CS | CONST_PERSISTENT);
 289 #endif
 290         REGISTER_LONG_CONSTANT("SI_QUEUE",   SI_QUEUE,   CONST_CS | CONST_PERSISTENT);
 291         REGISTER_LONG_CONSTANT("SI_TIMER",   SI_TIMER,   CONST_CS | CONST_PERSISTENT);
 292         REGISTER_LONG_CONSTANT("SI_MESGQ",   SI_MESGQ,   CONST_CS | CONST_PERSISTENT);
 293         REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
 294 #ifdef SI_SIGIO
 295         REGISTER_LONG_CONSTANT("SI_SIGIO",   SI_SIGIO,   CONST_CS | CONST_PERSISTENT);
 296 #endif
 297 #ifdef SI_TKILL
 298         REGISTER_LONG_CONSTANT("SI_TKILL",   SI_TKILL,   CONST_CS | CONST_PERSISTENT);
 299 #endif
 300 
 301         /* si_code for SIGCHILD */
 302 #ifdef CLD_EXITED
 303         REGISTER_LONG_CONSTANT("CLD_EXITED",    CLD_EXITED,    CONST_CS | CONST_PERSISTENT);
 304 #endif
 305 #ifdef CLD_KILLED
 306         REGISTER_LONG_CONSTANT("CLD_KILLED",    CLD_KILLED,    CONST_CS | CONST_PERSISTENT);
 307 #endif
 308 #ifdef CLD_DUMPED
 309         REGISTER_LONG_CONSTANT("CLD_DUMPED",    CLD_DUMPED,    CONST_CS | CONST_PERSISTENT);
 310 #endif
 311 #ifdef CLD_TRAPPED
 312         REGISTER_LONG_CONSTANT("CLD_TRAPPED",   CLD_TRAPPED,   CONST_CS | CONST_PERSISTENT);
 313 #endif
 314 #ifdef CLD_STOPPED
 315         REGISTER_LONG_CONSTANT("CLD_STOPPED",   CLD_STOPPED,   CONST_CS | CONST_PERSISTENT);
 316 #endif
 317 #ifdef CLD_CONTINUED
 318         REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
 319 #endif
 320 
 321         /* si_code for SIGTRAP */
 322 #ifdef TRAP_BRKPT
 323         REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
 324 #endif
 325 #ifdef TRAP_TRACE
 326         REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
 327 #endif
 328 
 329         /* si_code for SIGPOLL */
 330 #ifdef POLL_IN
 331         REGISTER_LONG_CONSTANT("POLL_IN",  POLL_IN,  CONST_CS | CONST_PERSISTENT);
 332 #endif
 333 #ifdef POLL_OUT
 334         REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
 335 #endif
 336 #ifdef POLL_MSG
 337         REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
 338 #endif
 339 #ifdef POLL_ERR
 340         REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
 341 #endif
 342 #ifdef POLL_PRI
 343         REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
 344 #endif
 345 #ifdef POLL_HUP
 346         REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
 347 #endif
 348 
 349 #ifdef ILL_ILLOPC
 350         REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
 351 #endif
 352 #ifdef ILL_ILLOPN
 353         REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
 354 #endif
 355 #ifdef ILL_ILLADR
 356         REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
 357 #endif
 358 #ifdef ILL_ILLTRP
 359         REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
 360 #endif
 361 #ifdef ILL_PRVOPC
 362         REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
 363 #endif
 364 #ifdef ILL_PRVREG
 365         REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
 366 #endif
 367 #ifdef ILL_COPROC
 368         REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
 369 #endif
 370 #ifdef ILL_BADSTK
 371         REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
 372 #endif
 373 
 374 #ifdef FPE_INTDIV
 375         REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
 376 #endif
 377 #ifdef FPE_INTOVF
 378         REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
 379 #endif
 380 #ifdef FPE_FLTDIV
 381         REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
 382 #endif
 383 #ifdef FPE_FLTOVF
 384         REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
 385 #endif
 386 #ifdef FPE_FLTUND
 387         REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
 388 #endif
 389 #ifdef FPE_FLTRES
 390         REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
 391 #endif
 392 #ifdef FPE_FLTINV
 393         REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
 394 #endif
 395 #ifdef FPE_FLTSUB
 396         REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
 397 #endif
 398 
 399 #ifdef SEGV_MAPERR
 400         REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
 401 #endif
 402 #ifdef SEGV_ACCERR
 403         REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
 404 #endif
 405 
 406 #ifdef BUS_ADRALN
 407         REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
 408 #endif
 409 #ifdef BUS_ADRERR
 410         REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
 411 #endif
 412 #ifdef BUS_OBJERR
 413         REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
 414 #endif
 415 #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */
 416         /* }}} */
 417 }
 418 
 419 static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
 420 {
 421 #ifdef EINTR
 422         REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
 423 #endif
 424 #ifdef ECHILD
 425         REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
 426 #endif
 427 #ifdef EINVAL
 428         REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
 429 #endif
 430 #ifdef EAGAIN
 431         REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
 432 #endif
 433 #ifdef ESRCH
 434         REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
 435 #endif
 436 #ifdef EACCES
 437         REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
 438 #endif
 439 #ifdef EPERM
 440         REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
 441 #endif
 442 #ifdef ENOMEM
 443         REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
 444 #endif
 445 #ifdef E2BIG
 446         REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
 447 #endif
 448 #ifdef EFAULT
 449         REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
 450 #endif
 451 #ifdef EIO
 452         REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
 453 #endif
 454 #ifdef EISDIR
 455         REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
 456 #endif
 457 #ifdef ELIBBAD
 458         REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
 459 #endif
 460 #ifdef ELOOP
 461         REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
 462 #endif
 463 #ifdef EMFILE
 464         REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
 465 #endif
 466 #ifdef ENAMETOOLONG
 467         REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
 468 #endif
 469 #ifdef ENFILE
 470         REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
 471 #endif
 472 #ifdef ENOENT
 473         REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
 474 #endif
 475 #ifdef ENOEXEC
 476         REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
 477 #endif
 478 #ifdef ENOTDIR
 479         REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
 480 #endif
 481 #ifdef ETXTBSY
 482         REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
 483 #endif
 484 }
 485 
 486 static PHP_GINIT_FUNCTION(pcntl)
 487 {
 488         memset(pcntl_globals, 0, sizeof(*pcntl_globals));
 489 }
 490 
 491 PHP_RINIT_FUNCTION(pcntl)
 492 {
 493         zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
 494         PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
 495         return SUCCESS;
 496 }
 497 
 498 PHP_MINIT_FUNCTION(pcntl)
 499 {
 500         php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
 501         php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
 502         php_add_tick_function(pcntl_signal_dispatch);
 503 
 504         return SUCCESS;
 505 }
 506 
 507 PHP_MSHUTDOWN_FUNCTION(pcntl)
 508 {
 509         return SUCCESS;
 510 }
 511 
 512 PHP_RSHUTDOWN_FUNCTION(pcntl)
 513 {
 514         struct php_pcntl_pending_signal *sig;
 515 
 516         /* FIXME: if a signal is delivered after this point, things will go pear shaped;
 517          * need to remove signal handlers */
 518         zend_hash_destroy(&PCNTL_G(php_signal_table));
 519         while (PCNTL_G(head)) {
 520                 sig = PCNTL_G(head);
 521                 PCNTL_G(head) = sig->next;
 522                 efree(sig);
 523         }
 524         while (PCNTL_G(spares)) {
 525                 sig = PCNTL_G(spares);
 526                 PCNTL_G(spares) = sig->next;
 527                 efree(sig);
 528         }
 529         return SUCCESS;
 530 }
 531 
 532 PHP_MINFO_FUNCTION(pcntl)
 533 {
 534         php_info_print_table_start();
 535         php_info_print_table_header(2, "pcntl support", "enabled");
 536         php_info_print_table_end();
 537 }
 538 
 539 /* {{{ proto int pcntl_fork(void)
 540    Forks the currently running process following the same behavior as the UNIX fork() system call*/
 541 PHP_FUNCTION(pcntl_fork)
 542 {
 543         pid_t id;
 544 
 545         id = fork();
 546         if (id == -1) {
 547                 PCNTL_G(last_error) = errno;
 548                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
 549         }
 550 
 551         RETURN_LONG((long) id);
 552 }
 553 /* }}} */
 554 
 555 /* {{{ proto int pcntl_alarm(int seconds)
 556    Set an alarm clock for delivery of a signal*/
 557 PHP_FUNCTION(pcntl_alarm)
 558 {
 559         long seconds;
 560 
 561         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
 562                 return;
 563 
 564         RETURN_LONG ((long) alarm(seconds));
 565 }
 566 /* }}} */
 567 
 568 /* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
 569    Waits on or returns the status of a forked child as defined by the waitpid() system call */
 570 PHP_FUNCTION(pcntl_waitpid)
 571 {
 572         long pid, options = 0;
 573         zval *z_status = NULL;
 574         int status;
 575         pid_t child_id;
 576 
 577         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
 578                 return;
 579 
 580         convert_to_long_ex(&z_status);
 581 
 582         status = Z_LVAL_P(z_status);
 583 
 584         child_id = waitpid((pid_t) pid, &status, options);
 585 
 586         if (child_id < 0) {
 587                 PCNTL_G(last_error) = errno;
 588         }
 589 
 590         Z_LVAL_P(z_status) = status;
 591 
 592         RETURN_LONG((long) child_id);
 593 }
 594 /* }}} */
 595 
 596 /* {{{ proto int pcntl_wait(int &status)
 597    Waits on or returns the status of a forked child as defined by the waitpid() system call */
 598 PHP_FUNCTION(pcntl_wait)
 599 {
 600         long options = 0;
 601         zval *z_status = NULL;
 602         int status;
 603         pid_t child_id;
 604 
 605         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
 606                 return;
 607 
 608         convert_to_long_ex(&z_status);
 609 
 610         status = Z_LVAL_P(z_status);
 611 #ifdef HAVE_WAIT3
 612         if(options) {
 613                 child_id = wait3(&status, options, NULL);
 614         }
 615         else {
 616                 child_id = wait(&status);
 617         }
 618 #else
 619         child_id = wait(&status);
 620 #endif
 621         if (child_id < 0) {
 622                 PCNTL_G(last_error) = errno;
 623         }
 624 
 625         Z_LVAL_P(z_status) = status;
 626 
 627         RETURN_LONG((long) child_id);
 628 }
 629 /* }}} */
 630 
 631 /* {{{ proto bool pcntl_wifexited(int status)
 632    Returns true if the child status code represents a successful exit */
 633 PHP_FUNCTION(pcntl_wifexited)
 634 {
 635 #ifdef WIFEXITED
 636         long status_word;
 637 
 638         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 639                return;
 640         }
 641 
 642         if (WIFEXITED(status_word))
 643                 RETURN_TRUE;
 644 #endif
 645         RETURN_FALSE;
 646 }
 647 /* }}} */
 648 
 649 /* {{{ proto bool pcntl_wifstopped(int status)
 650    Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
 651 PHP_FUNCTION(pcntl_wifstopped)
 652 {
 653 #ifdef WIFSTOPPED
 654         long status_word;
 655 
 656         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 657                return;
 658         }
 659 
 660         if (WIFSTOPPED(status_word))
 661                 RETURN_TRUE;
 662 #endif
 663         RETURN_FALSE;
 664 }
 665 /* }}} */
 666 
 667 /* {{{ proto bool pcntl_wifsignaled(int status)
 668    Returns true if the child status code represents a process that was terminated due to a signal */
 669 PHP_FUNCTION(pcntl_wifsignaled)
 670 {
 671 #ifdef WIFSIGNALED
 672         long status_word;
 673 
 674         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 675                return;
 676         }
 677 
 678         if (WIFSIGNALED(status_word))
 679                 RETURN_TRUE;
 680 #endif
 681         RETURN_FALSE;
 682 }
 683 /* }}} */
 684 
 685 /* {{{ proto int pcntl_wexitstatus(int status)
 686    Returns the status code of a child's exit */
 687 PHP_FUNCTION(pcntl_wexitstatus)
 688 {
 689 #ifdef WEXITSTATUS
 690         long status_word;
 691 
 692         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 693                return;
 694         }
 695 
 696         RETURN_LONG(WEXITSTATUS(status_word));
 697 #else
 698         RETURN_FALSE;
 699 #endif
 700 }
 701 /* }}} */
 702 
 703 /* {{{ proto int pcntl_wtermsig(int status)
 704    Returns the number of the signal that terminated the process who's status code is passed  */
 705 PHP_FUNCTION(pcntl_wtermsig)
 706 {
 707 #ifdef WTERMSIG
 708         long status_word;
 709 
 710         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 711                return;
 712         }
 713 
 714         RETURN_LONG(WTERMSIG(status_word));
 715 #else
 716         RETURN_FALSE;
 717 #endif
 718 }
 719 /* }}} */
 720 
 721 /* {{{ proto int pcntl_wstopsig(int status)
 722    Returns the number of the signal that caused the process to stop who's status code is passed */
 723 PHP_FUNCTION(pcntl_wstopsig)
 724 {
 725 #ifdef WSTOPSIG
 726         long status_word;
 727 
 728         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
 729                return;
 730         }
 731 
 732         RETURN_LONG(WSTOPSIG(status_word));
 733 #else
 734         RETURN_FALSE;
 735 #endif
 736 }
 737 /* }}} */
 738 
 739 /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
 740    Executes specified program in current process space as defined by exec(2) */
 741 PHP_FUNCTION(pcntl_exec)
 742 {
 743         zval *args = NULL, *envs = NULL;
 744         zval **element;
 745         HashTable *args_hash, *envs_hash;
 746         int argc = 0, argi = 0;
 747         int envc = 0, envi = 0;
 748         int return_val = 0;
 749         char **argv = NULL, **envp = NULL;
 750         char **current_arg, **pair;
 751         int pair_length;
 752         char *key;
 753         uint key_length;
 754         char *path;
 755         int path_len;
 756         ulong key_num;
 757 
 758         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
 759                 return;
 760         }
 761 
 762         if (ZEND_NUM_ARGS() > 1) {
 763                 /* Build argument list */
 764                 args_hash = HASH_OF(args);
 765                 argc = zend_hash_num_elements(args_hash);
 766 
 767                 argv = safe_emalloc((argc + 2), sizeof(char *), 0);
 768                 *argv = path;
 769                 for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
 770                         (argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
 771                         (argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
 772 
 773                         convert_to_string_ex(element);
 774                         *current_arg = Z_STRVAL_PP(element);
 775                 }
 776                 *(current_arg) = NULL;
 777         } else {
 778                 argv = emalloc(2 * sizeof(char *));
 779                 *argv = path;
 780                 *(argv+1) = NULL;
 781         }
 782 
 783         if ( ZEND_NUM_ARGS() == 3 ) {
 784                 /* Build environment pair list */
 785                 envs_hash = HASH_OF(envs);
 786                 envc = zend_hash_num_elements(envs_hash);
 787 
 788                 envp = safe_emalloc((envc + 1), sizeof(char *), 0);
 789                 for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
 790                         (envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
 791                         (envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
 792                         switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
 793                                 case HASH_KEY_IS_LONG:
 794                                         key = emalloc(101);
 795                                         snprintf(key, 100, "%ld", key_num);
 796                                         key_length = strlen(key);
 797                                         break;
 798                                 case HASH_KEY_NON_EXISTENT:
 799                                         pair--;
 800                                         continue;
 801                         }
 802 
 803                         convert_to_string_ex(element);
 804 
 805                         /* Length of element + equal sign + length of key + null */
 806                         pair_length = Z_STRLEN_PP(element) + key_length + 2;
 807                         *pair = emalloc(pair_length);
 808                         strlcpy(*pair, key, key_length);
 809                         strlcat(*pair, "=", pair_length);
 810                         strlcat(*pair, Z_STRVAL_PP(element), pair_length);
 811 
 812                         /* Cleanup */
 813                         if (return_val == HASH_KEY_IS_LONG) efree(key);
 814                 }
 815                 *(pair) = NULL;
 816 
 817                 if (execve(path, argv, envp) == -1) {
 818                         PCNTL_G(last_error) = errno;
 819                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
 820                 }
 821 
 822                 /* Cleanup */
 823                 for (pair = envp; *pair != NULL; pair++) efree(*pair);
 824                 efree(envp);
 825         } else {
 826 
 827                 if (execv(path, argv) == -1) {
 828                         PCNTL_G(last_error) = errno;
 829                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
 830                 }
 831         }
 832 
 833         efree(argv);
 834 
 835         RETURN_FALSE;
 836 }
 837 /* }}} */
 838 
 839 /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
 840    Assigns a system signal handler to a PHP function */
 841 PHP_FUNCTION(pcntl_signal)
 842 {
 843         zval *handle, **dest_handle = NULL;
 844         char *func_name;
 845         long signo;
 846         zend_bool restart_syscalls = 1;
 847 
 848         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
 849                 return;
 850         }
 851 
 852         if (signo < 1 || signo > 32) {
 853                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid signal");
 854                 RETURN_FALSE;
 855         }
 856 
 857         if (!PCNTL_G(spares)) {
 858                 /* since calling malloc() from within a signal handler is not portable,
 859                  * pre-allocate a few records for recording signals */
 860                 int i;
 861                 for (i = 0; i < 32; i++) {
 862                         struct php_pcntl_pending_signal *psig;
 863 
 864                         psig = emalloc(sizeof(*psig));
 865                         psig->next = PCNTL_G(spares);
 866                         PCNTL_G(spares) = psig;
 867                 }
 868         }
 869 
 870         /* Special long value case for SIG_DFL and SIG_IGN */
 871         if (Z_TYPE_P(handle) == IS_LONG) {
 872                 if (Z_LVAL_P(handle) != (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
 873                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
 874                         RETURN_FALSE;
 875                 }
 876                 if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
 877                         PCNTL_G(last_error) = errno;
 878                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
 879                         RETURN_FALSE;
 880                 }
 881                 zend_hash_index_del(&PCNTL_G(php_signal_table), signo);
 882                 RETURN_TRUE;
 883         }
 884 
 885         if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
 886                 PCNTL_G(last_error) = EINVAL;
 887                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
 888                 efree(func_name);
 889                 RETURN_FALSE;
 890         }
 891         efree(func_name);
 892 
 893         /* Add the function name to our signal table */
 894         zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
 895         if (dest_handle) zval_add_ref(dest_handle);
 896 
 897         if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
 898                 PCNTL_G(last_error) = errno;
 899                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
 900                 RETURN_FALSE;
 901         }
 902         RETURN_TRUE;
 903 }
 904 /* }}} */
 905 
 906 /* {{{ proto bool pcntl_signal_dispatch()
 907    Dispatch signals to signal handlers */
 908 PHP_FUNCTION(pcntl_signal_dispatch)
 909 {
 910         pcntl_signal_dispatch();
 911         RETURN_TRUE;
 912 }
 913 /* }}} */
 914 
 915 #ifdef HAVE_SIGPROCMASK
 916 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
 917    Examine and change blocked signals */
 918 PHP_FUNCTION(pcntl_sigprocmask)
 919 {
 920         long          how, signo;
 921         zval         *user_set, *user_oldset = NULL, **user_signo;
 922         sigset_t      set, oldset;
 923         HashPosition  pos;
 924 
 925         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la|z", &how, &user_set, &user_oldset) == FAILURE) {
 926                 return;
 927         }
 928 
 929         if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
 930                 PCNTL_G(last_error) = errno;
 931                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
 932                 RETURN_FALSE;
 933         }
 934 
 935         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
 936         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
 937         {
 938                 if (Z_TYPE_PP(user_signo) != IS_LONG) {
 939                         SEPARATE_ZVAL(user_signo);
 940                         convert_to_long_ex(user_signo);
 941                 }
 942                 signo = Z_LVAL_PP(user_signo);
 943                 if (sigaddset(&set, signo) != 0) {
 944                         PCNTL_G(last_error) = errno;
 945                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
 946                         RETURN_FALSE;
 947                 }
 948                 zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
 949         }
 950 
 951         if (sigprocmask(how, &set, &oldset) != 0) {
 952                 PCNTL_G(last_error) = errno;
 953                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
 954                 RETURN_FALSE;
 955         }
 956 
 957         if (user_oldset != NULL) {
 958                 if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
 959                         zval_dtor(user_oldset);
 960                         array_init(user_oldset);
 961                 } else {
 962                         zend_hash_clean(Z_ARRVAL_P(user_oldset));
 963                 }
 964                 for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) {
 965                         if (sigismember(&oldset, signo) != 1) {
 966                                 continue;
 967                         }
 968                         add_next_index_long(user_oldset, signo);
 969                 }
 970         }
 971 
 972         RETURN_TRUE;
 973 }
 974 /* }}} */
 975 #endif
 976 
 977 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
 978 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
 979 {
 980         zval            *user_set, **user_signo, *user_siginfo = NULL;
 981         long             tv_sec = 0, tv_nsec = 0;
 982         sigset_t         set;
 983         HashPosition     pos;
 984         int              signo;
 985         siginfo_t        siginfo;
 986         struct timespec  timeout;
 987 
 988         if (timedwait) {
 989                 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
 990                         return;
 991                 }
 992         } else {
 993                 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) {
 994                         return;
 995                 }
 996         }
 997 
 998         if (sigemptyset(&set) != 0) {
 999                 PCNTL_G(last_error) = errno;
1000                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1001                 RETURN_FALSE;
1002         }
1003 
1004         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
1005         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
1006         {
1007                 if (Z_TYPE_PP(user_signo) != IS_LONG) {
1008                         SEPARATE_ZVAL(user_signo);
1009                         convert_to_long_ex(user_signo);
1010                 }
1011                 signo = Z_LVAL_PP(user_signo);
1012                 if (sigaddset(&set, signo) != 0) {
1013                         PCNTL_G(last_error) = errno;
1014                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1015                         RETURN_FALSE;
1016                 }
1017                 zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
1018         }
1019 
1020         if (timedwait) {
1021                 timeout.tv_sec  = (time_t) tv_sec;
1022                 timeout.tv_nsec = tv_nsec;
1023                 signo = sigtimedwait(&set, &siginfo, &timeout);
1024         } else {
1025                 signo = sigwaitinfo(&set, &siginfo);
1026         }
1027         if (signo == -1 && errno != EAGAIN) {
1028                 PCNTL_G(last_error) = errno;
1029                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1030         }
1031 
1032         /*
1033          * sigtimedwait and sigwaitinfo can return 0 on success on some
1034          * platforms, e.g. NetBSD
1035          */
1036         if (!signo && siginfo.si_signo) {
1037                 signo = siginfo.si_signo;
1038         }
1039 
1040         if (signo > 0 && user_siginfo) {
1041                 if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
1042                         zval_dtor(user_siginfo);
1043                         array_init(user_siginfo);
1044                 } else {
1045                         zend_hash_clean(Z_ARRVAL_P(user_siginfo));
1046                 }
1047                 add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo);
1048                 add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno);
1049                 add_assoc_long_ex(user_siginfo, "code",  sizeof("code"),  siginfo.si_code);
1050                 switch(signo) {
1051 #ifdef SIGCHLD
1052                         case SIGCHLD:
1053                                 add_assoc_long_ex(user_siginfo,   "status", sizeof("status"), siginfo.si_status);
1054 # ifdef si_utime
1055                                 add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime"),  siginfo.si_utime);
1056 # endif
1057 # ifdef si_stime
1058                                 add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime"),  siginfo.si_stime);
1059 # endif
1060                                 add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid"),    siginfo.si_pid);
1061                                 add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid"),    siginfo.si_uid);
1062                                 break;
1063 #endif
1064                         case SIGILL:
1065                         case SIGFPE:
1066                         case SIGSEGV:
1067                         case SIGBUS:
1068                                 add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr);
1069                                 break;
1070 #ifdef SIGPOLL
1071                         case SIGPOLL:
1072                                 add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band);
1073 # ifdef si_fd
1074                                 add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd"),   siginfo.si_fd);
1075 # endif
1076                                 break;
1077 #endif
1078                         EMPTY_SWITCH_DEFAULT_CASE();
1079                 }
1080         }
1081 
1082         RETURN_LONG(signo);
1083 }
1084 /* }}} */
1085 
1086 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1087    Synchronously wait for queued signals */
1088 PHP_FUNCTION(pcntl_sigwaitinfo)
1089 {
1090         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1091 }
1092 /* }}} */
1093 
1094 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1095    Wait for queued signals */
1096 PHP_FUNCTION(pcntl_sigtimedwait)
1097 {
1098         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1099 }
1100 /* }}} */
1101 #endif
1102 
1103 #ifdef HAVE_GETPRIORITY
1104 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
1105    Get the priority of any process */
1106 PHP_FUNCTION(pcntl_getpriority)
1107 {
1108         long who = PRIO_PROCESS;
1109         long pid = getpid();
1110         int pri;
1111 
1112         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
1113                 RETURN_FALSE;
1114         }
1115 
1116         /* needs to be cleared, since any returned value is valid */
1117         errno = 0;
1118 
1119         pri = getpriority(who, pid);
1120 
1121         if (errno) {
1122                 PCNTL_G(last_error) = errno;
1123                 switch (errno) {
1124                         case ESRCH:
1125                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1126                                 break;
1127                         case EINVAL:
1128                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1129                                 break;
1130                         default:
1131                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno);
1132                                 break;
1133                 }
1134                 RETURN_FALSE;
1135         }
1136 
1137         RETURN_LONG(pri);
1138 }
1139 /* }}} */
1140 #endif
1141 
1142 #ifdef HAVE_SETPRIORITY
1143 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
1144    Change the priority of any process */
1145 PHP_FUNCTION(pcntl_setpriority)
1146 {
1147         long who = PRIO_PROCESS;
1148         long pid = getpid();
1149         long pri;
1150 
1151         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
1152                 RETURN_FALSE;
1153         }
1154 
1155         if (setpriority(who, pid, pri)) {
1156                 PCNTL_G(last_error) = errno;
1157                 switch (errno) {
1158                         case ESRCH:
1159                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1160                                 break;
1161                         case EINVAL:
1162                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1163                                 break;
1164                         case EPERM:
1165                                 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);
1166                                 break;
1167                         case EACCES:
1168                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
1169                                 break;
1170                         default:
1171                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno);
1172                                 break;
1173                 }
1174                 RETURN_FALSE;
1175         }
1176 
1177         RETURN_TRUE;
1178 }
1179 /* }}} */
1180 #endif
1181 
1182 /* {{{ proto int pcntl_get_last_error(void)
1183    Retrieve the error number set by the last pcntl function which failed. */
1184 PHP_FUNCTION(pcntl_get_last_error)
1185 {
1186         RETURN_LONG(PCNTL_G(last_error));
1187 }
1188 /* }}} */
1189 
1190 /* {{{ proto string pcntl_strerror(int errno)
1191    Retrieve the system error message associated with the given errno. */
1192 PHP_FUNCTION(pcntl_strerror)
1193 {
1194         long error;
1195 
1196         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
1197                 RETURN_FALSE;
1198         }
1199 
1200         RETURN_STRING(strerror(error), 1);
1201 }
1202 /* }}} */
1203 
1204 /* Our custom signal handler that calls the appropriate php_function */
1205 static void pcntl_signal_handler(int signo)
1206 {
1207         struct php_pcntl_pending_signal *psig;
1208         TSRMLS_FETCH();
1209 
1210         psig = PCNTL_G(spares);
1211         if (!psig) {
1212                 /* oops, too many signals for us to track, so we'll forget about this one */
1213                 return;
1214         }
1215         PCNTL_G(spares) = psig->next;
1216 
1217         psig->signo = signo;
1218         psig->next = NULL;
1219 
1220         /* the head check is important, as the tick handler cannot atomically clear both
1221          * the head and tail */
1222         if (PCNTL_G(head) && PCNTL_G(tail)) {
1223                 PCNTL_G(tail)->next = psig;
1224         } else {
1225                 PCNTL_G(head) = psig;
1226         }
1227         PCNTL_G(tail) = psig;
1228         PCNTL_G(pending_signals) = 1;
1229 }
1230 
1231 void pcntl_signal_dispatch()
1232 {
1233         zval *param, **handle, *retval;
1234         struct php_pcntl_pending_signal *queue, *next;
1235         sigset_t mask;
1236         sigset_t old_mask;
1237         TSRMLS_FETCH();
1238 
1239         if(!PCNTL_G(pending_signals)) {
1240                 return;
1241         }
1242                 
1243         /* Mask all signals */
1244         sigfillset(&mask);
1245         sigprocmask(SIG_BLOCK, &mask, &old_mask);
1246 
1247         /* Bail if the queue is empty or if we are already playing the queue*/
1248         if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1249                 sigprocmask(SIG_SETMASK, &old_mask, NULL);
1250                 return;
1251         }
1252 
1253         /* Prevent reentrant handler calls */
1254         PCNTL_G(processing_signal_queue) = 1;
1255 
1256         queue = PCNTL_G(head);
1257         PCNTL_G(head) = NULL; /* simple stores are atomic */
1258 
1259         /* Allocate */
1260 
1261         while (queue) {
1262                 if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
1263                         MAKE_STD_ZVAL(retval);
1264                         MAKE_STD_ZVAL(param);
1265                         ZVAL_NULL(retval);
1266                         ZVAL_LONG(param, queue->signo);
1267 
1268                         /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
1269                         /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1270                         call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
1271                         zval_ptr_dtor(&param);
1272                         zval_ptr_dtor(&retval);
1273                 }
1274 
1275                 next = queue->next;
1276                 queue->next = PCNTL_G(spares);
1277                 PCNTL_G(spares) = queue;
1278                 queue = next;
1279         }
1280 
1281         PCNTL_G(pending_signals) = 0;
1282 
1283         /* Re-enable queue */
1284         PCNTL_G(processing_signal_queue) = 0;
1285 
1286         /* return signal mask to previous state */
1287         sigprocmask(SIG_SETMASK, &old_mask, NULL);
1288 }
1289 
1290 
1291 
1292 /*
1293  * Local variables:
1294  * tab-width: 4
1295  * c-basic-offset: 4
1296  * indent-tabs-mode: t
1297  * End:
1298  */

/* [<][>][^][v][top][bottom][index][help] */