PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/pcntl - pcntl.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 455 575 79.1 %
Date: 2019-05-06 Functions: 34 37 91.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 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             : #define PCNTL_DEBUG 0
      20             : 
      21             : #if PCNTL_DEBUG
      22             : #define DEBUG_OUT printf("DEBUG: ");printf
      23             : #define IF_DEBUG(z) z
      24             : #else
      25             : #define IF_DEBUG(z)
      26             : #endif
      27             : 
      28             : #ifdef HAVE_CONFIG_H
      29             : #include "config.h"
      30             : #endif
      31             : 
      32             : #include "php.h"
      33             : #include "php_ini.h"
      34             : #include "ext/standard/info.h"
      35             : #include "php_pcntl.h"
      36             : #include "php_signal.h"
      37             : #include "php_ticks.h"
      38             : 
      39             : #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
      40             : #include <sys/wait.h>
      41             : #include <sys/time.h>
      42             : #include <sys/resource.h>
      43             : #endif
      44             : 
      45             : #include <errno.h>
      46             : #ifdef HAVE_UNSHARE
      47             : #include <sched.h>
      48             : #endif
      49             : 
      50             : #ifndef NSIG
      51             : # ifdef SIGRTMAX
      52             : #  define NSIG (SIGRTMAX + 1)
      53             : # else
      54             : #  define NSIG 32
      55             : # endif
      56             : #endif
      57             : 
      58             : ZEND_DECLARE_MODULE_GLOBALS(pcntl)
      59             : static PHP_GINIT_FUNCTION(pcntl);
      60             : 
      61             : /* {{{ arginfo */
      62             : ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0)
      63             : ZEND_END_ARG_INFO()
      64             : 
      65             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
      66             :         ZEND_ARG_INFO(0, pid)
      67             :         ZEND_ARG_INFO(1, status)
      68             :         ZEND_ARG_INFO(0, options)
      69             :         ZEND_ARG_INFO(1, rusage)
      70             : ZEND_END_ARG_INFO()
      71             : 
      72             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
      73             :         ZEND_ARG_INFO(1, status)
      74             :         ZEND_ARG_INFO(0, options)
      75             :         ZEND_ARG_INFO(1, rusage)
      76             : ZEND_END_ARG_INFO()
      77             : 
      78             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
      79             :         ZEND_ARG_INFO(0, signo)
      80             :         ZEND_ARG_INFO(0, handler)
      81             :         ZEND_ARG_INFO(0, restart_syscalls)
      82             : ZEND_END_ARG_INFO()
      83             : 
      84             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal_get_handler, 0, 0, 1)
      85             :         ZEND_ARG_INFO(0, signo)
      86             : ZEND_END_ARG_INFO()
      87             : 
      88             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
      89             :         ZEND_ARG_INFO(0, how)
      90             :         ZEND_ARG_INFO(0, set)
      91             :         ZEND_ARG_INFO(1, oldset)
      92             : ZEND_END_ARG_INFO()
      93             : 
      94             : #ifdef HAVE_STRUCT_SIGINFO_T
      95             : # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
      96             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
      97             :         ZEND_ARG_INFO(0, set)
      98             :         ZEND_ARG_INFO(1, info)
      99             : ZEND_END_ARG_INFO()
     100             : 
     101             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
     102             :         ZEND_ARG_INFO(0, set)
     103             :         ZEND_ARG_INFO(1, info)
     104             :         ZEND_ARG_INFO(0, seconds)
     105             :         ZEND_ARG_INFO(0, nanoseconds)
     106             : ZEND_END_ARG_INFO()
     107             : # endif
     108             : #endif
     109             : 
     110             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
     111             :         ZEND_ARG_INFO(0, status)
     112             : ZEND_END_ARG_INFO()
     113             : 
     114             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1)
     115             :         ZEND_ARG_INFO(0, status)
     116             : ZEND_END_ARG_INFO()
     117             : 
     118             : #ifdef HAVE_WCONTINUED
     119             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifcontinued, 0, 0, 1)
     120             :         ZEND_ARG_INFO(0, status)
     121             : ZEND_END_ARG_INFO()
     122             : #endif
     123             : 
     124             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1)
     125             :         ZEND_ARG_INFO(0, status)
     126             : ZEND_END_ARG_INFO()
     127             : 
     128             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1)
     129             :         ZEND_ARG_INFO(0, status)
     130             : ZEND_END_ARG_INFO()
     131             : 
     132             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1)
     133             :         ZEND_ARG_INFO(0, status)
     134             : ZEND_END_ARG_INFO()
     135             : 
     136             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1)
     137             :         ZEND_ARG_INFO(0, status)
     138             : ZEND_END_ARG_INFO()
     139             : 
     140             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1)
     141             :         ZEND_ARG_INFO(0, path)
     142             :         ZEND_ARG_INFO(0, args)
     143             :         ZEND_ARG_INFO(0, envs)
     144             : ZEND_END_ARG_INFO()
     145             : 
     146             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1)
     147             :         ZEND_ARG_INFO(0, seconds)
     148             : ZEND_END_ARG_INFO()
     149             : 
     150             : #ifdef HAVE_GETPRIORITY
     151             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0)
     152             :         ZEND_ARG_INFO(0, pid)
     153             :         ZEND_ARG_INFO(0, process_identifier)
     154             : ZEND_END_ARG_INFO()
     155             : #endif
     156             : 
     157             : #ifdef HAVE_SETPRIORITY
     158             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
     159             :         ZEND_ARG_INFO(0, priority)
     160             :         ZEND_ARG_INFO(0, pid)
     161             :         ZEND_ARG_INFO(0, process_identifier)
     162             : ZEND_END_ARG_INFO()
     163             : #endif
     164             : 
     165             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
     166             :         ZEND_ARG_INFO(0, errno)
     167             : ZEND_END_ARG_INFO()
     168             : 
     169             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_async_signals, 0, 0, 1)
     170             :         ZEND_ARG_INFO(0, on)
     171             : ZEND_END_ARG_INFO()
     172             : 
     173             : #ifdef HAVE_UNSHARE
     174             : ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_unshare, 0, 0, 1)
     175             :         ZEND_ARG_INFO(0, flags)
     176             : ZEND_END_ARG_INFO()
     177             : #endif
     178             : /* }}} */
     179             : 
     180             : static const zend_function_entry pcntl_functions[] = {
     181             :         PHP_FE(pcntl_fork,                      arginfo_pcntl_void)
     182             :         PHP_FE(pcntl_waitpid,           arginfo_pcntl_waitpid)
     183             :         PHP_FE(pcntl_wait,                      arginfo_pcntl_wait)
     184             :         PHP_FE(pcntl_signal,            arginfo_pcntl_signal)
     185             :         PHP_FE(pcntl_signal_get_handler,                arginfo_pcntl_signal_get_handler)
     186             :         PHP_FE(pcntl_signal_dispatch,   arginfo_pcntl_void)
     187             :         PHP_FE(pcntl_wifexited,         arginfo_pcntl_wifexited)
     188             :         PHP_FE(pcntl_wifstopped,        arginfo_pcntl_wifstopped)
     189             :         PHP_FE(pcntl_wifsignaled,       arginfo_pcntl_wifsignaled)
     190             :         PHP_FE(pcntl_wexitstatus,       arginfo_pcntl_wifexitstatus)
     191             :         PHP_FE(pcntl_wtermsig,          arginfo_pcntl_wtermsig)
     192             :         PHP_FE(pcntl_wstopsig,          arginfo_pcntl_wstopsig)
     193             :         PHP_FE(pcntl_exec,                      arginfo_pcntl_exec)
     194             :         PHP_FE(pcntl_alarm,                     arginfo_pcntl_alarm)
     195             :         PHP_FE(pcntl_get_last_error,    arginfo_pcntl_void)
     196             :         PHP_FALIAS(pcntl_errno, pcntl_get_last_error,   NULL)
     197             :         PHP_FE(pcntl_strerror,          arginfo_pcntl_strerror)
     198             : #ifdef HAVE_GETPRIORITY
     199             :         PHP_FE(pcntl_getpriority,       arginfo_pcntl_getpriority)
     200             : #endif
     201             : #ifdef HAVE_SETPRIORITY
     202             :         PHP_FE(pcntl_setpriority,       arginfo_pcntl_setpriority)
     203             : #endif
     204             : #ifdef HAVE_SIGPROCMASK
     205             :         PHP_FE(pcntl_sigprocmask,       arginfo_pcntl_sigprocmask)
     206             : #endif
     207             : #ifdef HAVE_STRUCT_SIGINFO_T
     208             : # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
     209             :         PHP_FE(pcntl_sigwaitinfo,       arginfo_pcntl_sigwaitinfo)
     210             :         PHP_FE(pcntl_sigtimedwait,      arginfo_pcntl_sigtimedwait)
     211             : # endif
     212             : #endif
     213             : #ifdef HAVE_WCONTINUED
     214             :         PHP_FE(pcntl_wifcontinued,      arginfo_pcntl_wifcontinued)
     215             : #endif
     216             :         PHP_FE(pcntl_async_signals,     arginfo_pcntl_async_signals)
     217             : #ifdef HAVE_UNSHARE
     218             :         PHP_FE(pcntl_unshare,           arginfo_pcntl_unshare)
     219             : #endif
     220             :         PHP_FE_END
     221             : };
     222             : 
     223             : zend_module_entry pcntl_module_entry = {
     224             :         STANDARD_MODULE_HEADER,
     225             :         "pcntl",
     226             :         pcntl_functions,
     227             :         PHP_MINIT(pcntl),
     228             :         PHP_MSHUTDOWN(pcntl),
     229             :         PHP_RINIT(pcntl),
     230             :         PHP_RSHUTDOWN(pcntl),
     231             :         PHP_MINFO(pcntl),
     232             :         PHP_PCNTL_VERSION,
     233             :         PHP_MODULE_GLOBALS(pcntl),
     234             :         PHP_GINIT(pcntl),
     235             :         NULL,
     236             :         NULL,
     237             :         STANDARD_MODULE_PROPERTIES_EX
     238             : };
     239             : 
     240             : #ifdef COMPILE_DL_PCNTL
     241             : #ifdef ZTS
     242             : ZEND_TSRMLS_CACHE_DEFINE()
     243             : #endif
     244             : ZEND_GET_MODULE(pcntl)
     245             : #endif
     246             : 
     247             : static void (*orig_interrupt_function)(zend_execute_data *execute_data);
     248             : 
     249             : #ifdef HAVE_STRUCT_SIGINFO_T
     250             : static void pcntl_signal_handler(int, siginfo_t*, void*);
     251             : static void pcntl_siginfo_to_zval(int, siginfo_t*, zval*);
     252             : #else
     253             : static void pcntl_signal_handler(int);
     254             : #endif
     255             : static void pcntl_signal_dispatch();
     256             : static void pcntl_interrupt_function(zend_execute_data *execute_data);
     257             : 
     258       23043 : void php_register_signal_constants(INIT_FUNC_ARGS)
     259             : {
     260             : 
     261             :         /* Wait Constants */
     262             : #ifdef WNOHANG
     263       23043 :         REGISTER_LONG_CONSTANT("WNOHANG",  (zend_long) WNOHANG, CONST_CS | CONST_PERSISTENT);
     264             : #endif
     265             : #ifdef WUNTRACED
     266       23043 :         REGISTER_LONG_CONSTANT("WUNTRACED",  (zend_long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
     267             : #endif
     268             : #ifdef HAVE_WCONTINUED
     269       23043 :         REGISTER_LONG_CONSTANT("WCONTINUED",  (zend_long) WCONTINUED, CONST_CS | CONST_PERSISTENT);
     270             : #endif
     271             : 
     272             :         /* Signal Constants */
     273       23043 :         REGISTER_LONG_CONSTANT("SIG_IGN",  (zend_long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
     274       23043 :         REGISTER_LONG_CONSTANT("SIG_DFL",  (zend_long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
     275       23043 :         REGISTER_LONG_CONSTANT("SIG_ERR",  (zend_long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
     276       23043 :         REGISTER_LONG_CONSTANT("SIGHUP",   (zend_long) SIGHUP,  CONST_CS | CONST_PERSISTENT);
     277       23043 :         REGISTER_LONG_CONSTANT("SIGINT",   (zend_long) SIGINT,  CONST_CS | CONST_PERSISTENT);
     278       23043 :         REGISTER_LONG_CONSTANT("SIGQUIT",  (zend_long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
     279       23043 :         REGISTER_LONG_CONSTANT("SIGILL",   (zend_long) SIGILL,  CONST_CS | CONST_PERSISTENT);
     280       23043 :         REGISTER_LONG_CONSTANT("SIGTRAP",  (zend_long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
     281       23043 :         REGISTER_LONG_CONSTANT("SIGABRT",  (zend_long) SIGABRT, CONST_CS | CONST_PERSISTENT);
     282             : #ifdef SIGIOT
     283       23043 :         REGISTER_LONG_CONSTANT("SIGIOT",   (zend_long) SIGIOT,  CONST_CS | CONST_PERSISTENT);
     284             : #endif
     285       23043 :         REGISTER_LONG_CONSTANT("SIGBUS",   (zend_long) SIGBUS,  CONST_CS | CONST_PERSISTENT);
     286       23043 :         REGISTER_LONG_CONSTANT("SIGFPE",   (zend_long) SIGFPE,  CONST_CS | CONST_PERSISTENT);
     287       23043 :         REGISTER_LONG_CONSTANT("SIGKILL",  (zend_long) SIGKILL, CONST_CS | CONST_PERSISTENT);
     288       23043 :         REGISTER_LONG_CONSTANT("SIGUSR1",  (zend_long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
     289       23043 :         REGISTER_LONG_CONSTANT("SIGSEGV",  (zend_long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
     290       23043 :         REGISTER_LONG_CONSTANT("SIGUSR2",  (zend_long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
     291       23043 :         REGISTER_LONG_CONSTANT("SIGPIPE",  (zend_long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
     292       23043 :         REGISTER_LONG_CONSTANT("SIGALRM",  (zend_long) SIGALRM, CONST_CS | CONST_PERSISTENT);
     293       23043 :         REGISTER_LONG_CONSTANT("SIGTERM",  (zend_long) SIGTERM, CONST_CS | CONST_PERSISTENT);
     294             : #ifdef SIGSTKFLT
     295       23043 :         REGISTER_LONG_CONSTANT("SIGSTKFLT",(zend_long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
     296             : #endif
     297             : #ifdef SIGCLD
     298       23043 :         REGISTER_LONG_CONSTANT("SIGCLD",   (zend_long) SIGCLD, CONST_CS | CONST_PERSISTENT);
     299             : #endif
     300             : #ifdef SIGCHLD
     301       23043 :         REGISTER_LONG_CONSTANT("SIGCHLD",  (zend_long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
     302             : #endif
     303       23043 :         REGISTER_LONG_CONSTANT("SIGCONT",  (zend_long) SIGCONT, CONST_CS | CONST_PERSISTENT);
     304       23043 :         REGISTER_LONG_CONSTANT("SIGSTOP",  (zend_long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
     305       23043 :         REGISTER_LONG_CONSTANT("SIGTSTP",  (zend_long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
     306       23043 :         REGISTER_LONG_CONSTANT("SIGTTIN",  (zend_long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
     307       23043 :         REGISTER_LONG_CONSTANT("SIGTTOU",  (zend_long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
     308       23043 :         REGISTER_LONG_CONSTANT("SIGURG",   (zend_long) SIGURG , CONST_CS | CONST_PERSISTENT);
     309       23043 :         REGISTER_LONG_CONSTANT("SIGXCPU",  (zend_long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
     310       23043 :         REGISTER_LONG_CONSTANT("SIGXFSZ",  (zend_long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
     311       23043 :         REGISTER_LONG_CONSTANT("SIGVTALRM",(zend_long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
     312       23043 :         REGISTER_LONG_CONSTANT("SIGPROF",  (zend_long) SIGPROF, CONST_CS | CONST_PERSISTENT);
     313       23043 :         REGISTER_LONG_CONSTANT("SIGWINCH", (zend_long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
     314             : #ifdef SIGPOLL
     315       23043 :         REGISTER_LONG_CONSTANT("SIGPOLL",  (zend_long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
     316             : #endif
     317       23043 :         REGISTER_LONG_CONSTANT("SIGIO",    (zend_long) SIGIO, CONST_CS | CONST_PERSISTENT);
     318             : #ifdef SIGPWR
     319       23043 :         REGISTER_LONG_CONSTANT("SIGPWR",   (zend_long) SIGPWR, CONST_CS | CONST_PERSISTENT);
     320             : #endif
     321             : #ifdef SIGSYS
     322       23043 :         REGISTER_LONG_CONSTANT("SIGSYS",   (zend_long) SIGSYS, CONST_CS | CONST_PERSISTENT);
     323       23043 :         REGISTER_LONG_CONSTANT("SIGBABY",  (zend_long) SIGSYS, CONST_CS | CONST_PERSISTENT);
     324             : #endif
     325             : #ifdef SIGRTMIN
     326       23043 :         REGISTER_LONG_CONSTANT("SIGRTMIN", (zend_long) SIGRTMIN, CONST_CS | CONST_PERSISTENT);
     327             : #endif
     328             : #ifdef SIGRTMAX
     329       23043 :         REGISTER_LONG_CONSTANT("SIGRTMAX", (zend_long) SIGRTMAX, CONST_CS | CONST_PERSISTENT);
     330             : #endif
     331             : 
     332             : #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
     333       23043 :         REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
     334       23043 :         REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
     335       23043 :         REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
     336             : #endif
     337             : 
     338             :         /* {{{ "how" argument for sigprocmask */
     339             : #ifdef HAVE_SIGPROCMASK
     340       23043 :         REGISTER_LONG_CONSTANT("SIG_BLOCK",   SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
     341       23043 :         REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT);
     342       23043 :         REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT);
     343             : #endif
     344             :         /* }}} */
     345             : 
     346             :         /* {{{ si_code */
     347             : #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
     348       23043 :         REGISTER_LONG_CONSTANT("SI_USER",    SI_USER,    CONST_CS | CONST_PERSISTENT);
     349             : #ifdef SI_NOINFO
     350             :         REGISTER_LONG_CONSTANT("SI_NOINFO",  SI_NOINFO,  CONST_CS | CONST_PERSISTENT);
     351             : #endif
     352             : #ifdef SI_KERNEL
     353       23043 :         REGISTER_LONG_CONSTANT("SI_KERNEL",  SI_KERNEL,  CONST_CS | CONST_PERSISTENT);
     354             : #endif
     355       23043 :         REGISTER_LONG_CONSTANT("SI_QUEUE",   SI_QUEUE,   CONST_CS | CONST_PERSISTENT);
     356       23043 :         REGISTER_LONG_CONSTANT("SI_TIMER",   SI_TIMER,   CONST_CS | CONST_PERSISTENT);
     357       23043 :         REGISTER_LONG_CONSTANT("SI_MESGQ",   SI_MESGQ,   CONST_CS | CONST_PERSISTENT);
     358       23043 :         REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
     359             : #ifdef SI_SIGIO
     360       23043 :         REGISTER_LONG_CONSTANT("SI_SIGIO",   SI_SIGIO,   CONST_CS | CONST_PERSISTENT);
     361             : #endif
     362             : #ifdef SI_TKILL
     363       23043 :         REGISTER_LONG_CONSTANT("SI_TKILL",   SI_TKILL,   CONST_CS | CONST_PERSISTENT);
     364             : #endif
     365             : 
     366             :         /* si_code for SIGCHILD */
     367             : #ifdef CLD_EXITED
     368       23043 :         REGISTER_LONG_CONSTANT("CLD_EXITED",    CLD_EXITED,    CONST_CS | CONST_PERSISTENT);
     369             : #endif
     370             : #ifdef CLD_KILLED
     371       23043 :         REGISTER_LONG_CONSTANT("CLD_KILLED",    CLD_KILLED,    CONST_CS | CONST_PERSISTENT);
     372             : #endif
     373             : #ifdef CLD_DUMPED
     374       23043 :         REGISTER_LONG_CONSTANT("CLD_DUMPED",    CLD_DUMPED,    CONST_CS | CONST_PERSISTENT);
     375             : #endif
     376             : #ifdef CLD_TRAPPED
     377       23043 :         REGISTER_LONG_CONSTANT("CLD_TRAPPED",   CLD_TRAPPED,   CONST_CS | CONST_PERSISTENT);
     378             : #endif
     379             : #ifdef CLD_STOPPED
     380       23043 :         REGISTER_LONG_CONSTANT("CLD_STOPPED",   CLD_STOPPED,   CONST_CS | CONST_PERSISTENT);
     381             : #endif
     382             : #ifdef CLD_CONTINUED
     383       23043 :         REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
     384             : #endif
     385             : 
     386             :         /* si_code for SIGTRAP */
     387             : #ifdef TRAP_BRKPT
     388       23043 :         REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
     389             : #endif
     390             : #ifdef TRAP_TRACE
     391       23043 :         REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
     392             : #endif
     393             : 
     394             :         /* si_code for SIGPOLL */
     395             : #ifdef POLL_IN
     396       23043 :         REGISTER_LONG_CONSTANT("POLL_IN",  POLL_IN,  CONST_CS | CONST_PERSISTENT);
     397             : #endif
     398             : #ifdef POLL_OUT
     399       23043 :         REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
     400             : #endif
     401             : #ifdef POLL_MSG
     402       23043 :         REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
     403             : #endif
     404             : #ifdef POLL_ERR
     405       23043 :         REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
     406             : #endif
     407             : #ifdef POLL_PRI
     408       23043 :         REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
     409             : #endif
     410             : #ifdef POLL_HUP
     411       23043 :         REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
     412             : #endif
     413             : 
     414             : #ifdef ILL_ILLOPC
     415       23043 :         REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
     416             : #endif
     417             : #ifdef ILL_ILLOPN
     418       23043 :         REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
     419             : #endif
     420             : #ifdef ILL_ILLADR
     421       23043 :         REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
     422             : #endif
     423             : #ifdef ILL_ILLTRP
     424       23043 :         REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
     425             : #endif
     426             : #ifdef ILL_PRVOPC
     427       23043 :         REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
     428             : #endif
     429             : #ifdef ILL_PRVREG
     430       23043 :         REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
     431             : #endif
     432             : #ifdef ILL_COPROC
     433       23043 :         REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
     434             : #endif
     435             : #ifdef ILL_BADSTK
     436       23043 :         REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
     437             : #endif
     438             : 
     439             : #ifdef FPE_INTDIV
     440       23043 :         REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
     441             : #endif
     442             : #ifdef FPE_INTOVF
     443       23043 :         REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
     444             : #endif
     445             : #ifdef FPE_FLTDIV
     446       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
     447             : #endif
     448             : #ifdef FPE_FLTOVF
     449       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
     450             : #endif
     451             : #ifdef FPE_FLTUND
     452       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
     453             : #endif
     454             : #ifdef FPE_FLTRES
     455       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
     456             : #endif
     457             : #ifdef FPE_FLTINV
     458       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
     459             : #endif
     460             : #ifdef FPE_FLTSUB
     461       23043 :         REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
     462             : #endif
     463             : 
     464             : #ifdef SEGV_MAPERR
     465       23043 :         REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
     466             : #endif
     467             : #ifdef SEGV_ACCERR
     468       23043 :         REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
     469             : #endif
     470             : 
     471             : #ifdef BUS_ADRALN
     472       23043 :         REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
     473             : #endif
     474             : #ifdef BUS_ADRERR
     475       23043 :         REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
     476             : #endif
     477             : #ifdef BUS_OBJERR
     478       23043 :         REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
     479             : #endif
     480             : #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */
     481             :         /* }}} */
     482             : 
     483             :         /* unshare(/clone) constants */
     484             : #ifdef HAVE_UNSHARE
     485       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWNS",         CLONE_NEWNS, CONST_CS | CONST_PERSISTENT);
     486             : #ifdef CLONE_NEWIPC
     487       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWIPC",                CLONE_NEWIPC, CONST_CS | CONST_PERSISTENT);
     488             : #endif
     489             : #ifdef CLONE_NEWUTS
     490       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWUTS",                CLONE_NEWUTS, CONST_CS | CONST_PERSISTENT);
     491             : #endif
     492             : #ifdef CLONE_NEWNET
     493       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWNET",                CLONE_NEWNET, CONST_CS | CONST_PERSISTENT);
     494             : #endif
     495             : #ifdef CLONE_NEWPID
     496       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWPID",                CLONE_NEWPID, CONST_CS | CONST_PERSISTENT);
     497             : #endif
     498             : #ifdef CLONE_NEWUSER
     499       23043 :         REGISTER_LONG_CONSTANT("CLONE_NEWUSER",               CLONE_NEWUSER, CONST_CS | CONST_PERSISTENT);
     500             : #endif
     501             : #ifdef CLONE_NEWCGROUP
     502             :         REGISTER_LONG_CONSTANT("CLONE_NEWCGROUP",     CLONE_NEWCGROUP, CONST_CS | CONST_PERSISTENT);
     503             : #endif
     504             : #endif
     505       23043 : }
     506             : 
     507       23043 : static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
     508             : {
     509             : #ifdef EINTR
     510       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
     511             : #endif
     512             : #ifdef ECHILD
     513       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
     514             : #endif
     515             : #ifdef EINVAL
     516       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
     517             : #endif
     518             : #ifdef EAGAIN
     519       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
     520             : #endif
     521             : #ifdef ESRCH
     522       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
     523             : #endif
     524             : #ifdef EACCES
     525       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
     526             : #endif
     527             : #ifdef EPERM
     528       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
     529             : #endif
     530             : #ifdef ENOMEM
     531       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
     532             : #endif
     533             : #ifdef E2BIG
     534       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
     535             : #endif
     536             : #ifdef EFAULT
     537       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
     538             : #endif
     539             : #ifdef EIO
     540       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
     541             : #endif
     542             : #ifdef EISDIR
     543       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
     544             : #endif
     545             : #ifdef ELIBBAD
     546       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
     547             : #endif
     548             : #ifdef ELOOP
     549       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
     550             : #endif
     551             : #ifdef EMFILE
     552       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
     553             : #endif
     554             : #ifdef ENAMETOOLONG
     555       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
     556             : #endif
     557             : #ifdef ENFILE
     558       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
     559             : #endif
     560             : #ifdef ENOENT
     561       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
     562             : #endif
     563             : #ifdef ENOEXEC
     564       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
     565             : #endif
     566             : #ifdef ENOTDIR
     567       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
     568             : #endif
     569             : #ifdef ETXTBSY
     570       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
     571             : #endif
     572             : #ifdef ENOSPC
     573       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(ENOSPC);
     574             : #endif
     575             : #ifdef EUSERS
     576       23043 :         REGISTER_PCNTL_ERRNO_CONSTANT(EUSERS);
     577             : #endif
     578       23043 : }
     579             : 
     580       23043 : static PHP_GINIT_FUNCTION(pcntl)
     581             : {
     582             : #if defined(COMPILE_DL_PCNTL) && defined(ZTS)
     583             :         ZEND_TSRMLS_CACHE_UPDATE();
     584             : #endif
     585       23043 :         memset(pcntl_globals, 0, sizeof(*pcntl_globals));
     586       23043 : }
     587             : 
     588       23055 : PHP_RINIT_FUNCTION(pcntl)
     589             : {
     590       23055 :         php_add_tick_function(pcntl_signal_dispatch, NULL);
     591       23055 :         zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
     592       23055 :         PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
     593       23055 :         PCNTL_G(async_signals) = 0;
     594       23055 :         return SUCCESS;
     595             : }
     596             : 
     597       23043 : PHP_MINIT_FUNCTION(pcntl)
     598             : {
     599       23043 :         php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
     600       23043 :         php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
     601       23043 :         orig_interrupt_function = zend_interrupt_function;
     602       23043 :         zend_interrupt_function = pcntl_interrupt_function;
     603             : 
     604       23043 :         return SUCCESS;
     605             : }
     606             : 
     607       23105 : PHP_MSHUTDOWN_FUNCTION(pcntl)
     608             : {
     609       23105 :         return SUCCESS;
     610             : }
     611             : 
     612       23122 : PHP_RSHUTDOWN_FUNCTION(pcntl)
     613             : {
     614             :         struct php_pcntl_pending_signal *sig;
     615             : 
     616             :         /* FIXME: if a signal is delivered after this point, things will go pear shaped;
     617             :          * need to remove signal handlers */
     618       23122 :         zend_hash_destroy(&PCNTL_G(php_signal_table));
     619       46245 :         while (PCNTL_G(head)) {
     620           1 :                 sig = PCNTL_G(head);
     621           1 :                 PCNTL_G(head) = sig->next;
     622           1 :                 efree(sig);
     623             :         }
     624       47023 :         while (PCNTL_G(spares)) {
     625         779 :                 sig = PCNTL_G(spares);
     626         779 :                 PCNTL_G(spares) = sig->next;
     627         779 :                 efree(sig);
     628             :         }
     629       23122 :         return SUCCESS;
     630             : }
     631             : 
     632         146 : PHP_MINFO_FUNCTION(pcntl)
     633             : {
     634         146 :         php_info_print_table_start();
     635         146 :         php_info_print_table_header(2, "pcntl support", "enabled");
     636         146 :         php_info_print_table_end();
     637         146 : }
     638             : 
     639             : /* {{{ proto int pcntl_fork(void)
     640             :    Forks the currently running process following the same behavior as the UNIX fork() system call*/
     641         115 : PHP_FUNCTION(pcntl_fork)
     642             : {
     643             :         pid_t id;
     644             : 
     645         115 :         id = fork();
     646         184 :         if (id == -1) {
     647           0 :                 PCNTL_G(last_error) = errno;
     648           0 :                 php_error_docref(NULL, E_WARNING, "Error %d", errno);
     649             :         }
     650             : 
     651         184 :         RETURN_LONG((zend_long) id);
     652             : }
     653             : /* }}} */
     654             : 
     655             : /* {{{ proto int pcntl_alarm(int seconds)
     656             :    Set an alarm clock for delivery of a signal*/
     657          47 : PHP_FUNCTION(pcntl_alarm)
     658             : {
     659             :         zend_long seconds;
     660             : 
     661          47 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &seconds) == FAILURE)
     662           0 :                 return;
     663             : 
     664          47 :         RETURN_LONG ((zend_long) alarm(seconds));
     665             : }
     666             : /* }}} */
     667             : 
     668             : #define PHP_RUSAGE_PARA(from, to, field) \
     669             :         add_assoc_long(to, #field, from.field)
     670             : #ifndef _OSD_POSIX
     671             :         #define PHP_RUSAGE_SPECIAL(from, to) \
     672             :                 PHP_RUSAGE_PARA(from, to, ru_oublock); \
     673             :                 PHP_RUSAGE_PARA(from, to, ru_inblock); \
     674             :                 PHP_RUSAGE_PARA(from, to, ru_msgsnd); \
     675             :                 PHP_RUSAGE_PARA(from, to, ru_msgrcv); \
     676             :                 PHP_RUSAGE_PARA(from, to, ru_maxrss); \
     677             :                 PHP_RUSAGE_PARA(from, to, ru_ixrss); \
     678             :                 PHP_RUSAGE_PARA(from, to, ru_idrss); \
     679             :                 PHP_RUSAGE_PARA(from, to, ru_minflt); \
     680             :                 PHP_RUSAGE_PARA(from, to, ru_majflt); \
     681             :                 PHP_RUSAGE_PARA(from, to, ru_nsignals); \
     682             :                 PHP_RUSAGE_PARA(from, to, ru_nvcsw); \
     683             :                 PHP_RUSAGE_PARA(from, to, ru_nivcsw); \
     684             :                 PHP_RUSAGE_PARA(from, to, ru_nswap);
     685             : #else /*_OSD_POSIX*/
     686             :         #define PHP_RUSAGE_SPECIAL(from, to)
     687             : #endif
     688             : 
     689             : #define PHP_RUSAGE_COMMON(from ,to) \
     690             :         PHP_RUSAGE_PARA(from, to, ru_utime.tv_usec); \
     691             :         PHP_RUSAGE_PARA(from, to, ru_utime.tv_sec); \
     692             :         PHP_RUSAGE_PARA(from, to, ru_stime.tv_usec); \
     693             :         PHP_RUSAGE_PARA(from, to, ru_stime.tv_sec);
     694             : 
     695             : #define PHP_RUSAGE_TO_ARRAY(from, to) \
     696             :         if (to) { \
     697             :                 PHP_RUSAGE_SPECIAL(from, to) \
     698             :                 PHP_RUSAGE_COMMON(from, to); \
     699             :         }
     700             : 
     701             : /* {{{ proto int pcntl_waitpid(int pid, int &status, int options, array &$rusage)
     702             :    Waits on or returns the status of a forked child as defined by the waitpid() system call */
     703          95 : PHP_FUNCTION(pcntl_waitpid)
     704             : {
     705          95 :         zend_long pid, options = 0;
     706          95 :         zval *z_status = NULL, *z_rusage = NULL;
     707             :         int status;
     708             :         pid_t child_id;
     709             : #ifdef HAVE_WAIT4
     710             :         struct rusage rusage;
     711             : #endif
     712             : 
     713          95 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|lz", &pid, &z_status, &options, &z_rusage) == FAILURE) {
     714           0 :                 return;
     715             :         }
     716             : 
     717         190 :         status = zval_get_long(z_status);
     718             : 
     719             : #ifdef HAVE_WAIT4
     720          95 :         if (z_rusage) {
     721          10 :                 z_rusage = zend_try_array_init(z_rusage);
     722           5 :                 if (!z_rusage) {
     723           0 :                         return;
     724             :                 }
     725             : 
     726           5 :                 memset(&rusage, 0, sizeof(struct rusage));
     727           5 :                 child_id = wait4((pid_t) pid, &status, options, &rusage);
     728             :         } else {
     729          90 :                 child_id = waitpid((pid_t) pid, &status, options);
     730             :         }
     731             : #else
     732             :         child_id = waitpid((pid_t) pid, &status, options);
     733             : #endif
     734             : 
     735          95 :         if (child_id < 0) {
     736           4 :                 PCNTL_G(last_error) = errno;
     737             :         }
     738             : 
     739             : #ifdef HAVE_WAIT4
     740          95 :         if (child_id > 0) {
     741          53 :                 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
     742             :         }
     743             : #endif
     744             : 
     745         190 :         ZEND_TRY_ASSIGN_REF_LONG(z_status, status);
     746             : 
     747          95 :         RETURN_LONG((zend_long) child_id);
     748             : }
     749             : /* }}} */
     750             : 
     751             : /* {{{ proto int pcntl_wait(int &status, int $options, array &$rusage)
     752             :    Waits on or returns the status of a forked child as defined by the waitpid() system call */
     753          12 : PHP_FUNCTION(pcntl_wait)
     754             : {
     755          12 :         zend_long options = 0;
     756          12 :         zval *z_status = NULL, *z_rusage = NULL;
     757             :         int status;
     758             :         pid_t child_id;
     759             : #ifdef HAVE_WAIT3
     760             :         struct rusage rusage;
     761             : #endif
     762             : 
     763          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|lz", &z_status, &options, &z_rusage) == FAILURE) {
     764           0 :                 return;
     765             :         }
     766             : 
     767          24 :         status = zval_get_long(z_status);
     768             : #ifdef HAVE_WAIT3
     769          12 :         if (z_rusage) {
     770          10 :                 z_rusage = zend_try_array_init(z_rusage);
     771           5 :                 if (!z_rusage) {
     772           0 :                         return;
     773             :                 }
     774             : 
     775           5 :                 memset(&rusage, 0, sizeof(struct rusage));
     776           5 :                 child_id = wait3(&status, options, &rusage);
     777           7 :         } else if (options) {
     778           2 :                 child_id = wait3(&status, options, NULL);
     779             :         } else {
     780           5 :                 child_id = wait(&status);
     781             :         }
     782             : #else
     783             :         child_id = wait(&status);
     784             : #endif
     785          12 :         if (child_id < 0) {
     786           5 :                 PCNTL_G(last_error) = errno;
     787             :         }
     788             : 
     789             : #ifdef HAVE_WAIT3
     790          12 :         if (child_id > 0) {
     791           7 :                 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
     792             :         }
     793             : #endif
     794             : 
     795          24 :         ZEND_TRY_ASSIGN_REF_LONG(z_status, status);
     796             : 
     797          12 :         RETURN_LONG((zend_long) child_id);
     798             : }
     799             : /* }}} */
     800             : 
     801             : #undef PHP_RUSAGE_PARA
     802             : #undef PHP_RUSAGE_SPECIAL
     803             : #undef PHP_RUSAGE_COMMON
     804             : #undef PHP_RUSAGE_TO_ARRAY
     805             : 
     806             : /* {{{ proto bool pcntl_wifexited(int status)
     807             :    Returns true if the child status code represents a successful exit */
     808           4 : PHP_FUNCTION(pcntl_wifexited)
     809             : {
     810             : #ifdef WIFEXITED
     811             :         zend_long status_word;
     812             :         int int_status_word;
     813             : 
     814           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     815           0 :                return;
     816             :         }
     817             : 
     818           4 :         int_status_word = (int) status_word;
     819           4 :         if (WIFEXITED(int_status_word))
     820           3 :                 RETURN_TRUE;
     821             : #endif
     822             : 
     823           1 :         RETURN_FALSE;
     824             : }
     825             : /* }}} */
     826             : 
     827             : /* {{{ proto bool pcntl_wifstopped(int status)
     828             :    Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
     829           2 : PHP_FUNCTION(pcntl_wifstopped)
     830             : {
     831             : #ifdef WIFSTOPPED
     832             :         zend_long status_word;
     833             :         int int_status_word;
     834             : 
     835           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     836           0 :                return;
     837             :         }
     838             : 
     839           2 :         int_status_word = (int) status_word;
     840           2 :         if (WIFSTOPPED(int_status_word))
     841           1 :                 RETURN_TRUE;
     842             : #endif
     843           1 :         RETURN_FALSE;
     844             : }
     845             : /* }}} */
     846             : 
     847             : /* {{{ proto bool pcntl_wifsignaled(int status)
     848             :    Returns true if the child status code represents a process that was terminated due to a signal */
     849           2 : PHP_FUNCTION(pcntl_wifsignaled)
     850             : {
     851             : #ifdef WIFSIGNALED
     852             :         zend_long status_word;
     853             :         int int_status_word;
     854             : 
     855           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     856           0 :                return;
     857             :         }
     858             : 
     859           2 :         int_status_word = (int) status_word;
     860           2 :         if (WIFSIGNALED(int_status_word))
     861           1 :                 RETURN_TRUE;
     862             : #endif
     863           1 :         RETURN_FALSE;
     864             : }
     865             : /* }}} */
     866             : /* {{{ proto bool pcntl_wifcontinued(int status)
     867             :    Returns true if the child status code represents a process that was resumed due to a SIGCONT signal */
     868           0 : PHP_FUNCTION(pcntl_wifcontinued)
     869             : {
     870             : #ifdef HAVE_WCONTINUED
     871             :         zend_long status_word;
     872             :         int int_status_word;
     873             : 
     874           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     875           0 :                return;
     876             :         }
     877             : 
     878           0 :         int_status_word = (int) status_word;
     879           0 :         if (WIFCONTINUED(int_status_word))
     880           0 :                 RETURN_TRUE;
     881             : #endif
     882           0 :         RETURN_FALSE;
     883             : }
     884             : /* }}} */
     885             : 
     886             : 
     887             : /* {{{ proto int pcntl_wexitstatus(int status)
     888             :    Returns the status code of a child's exit */
     889           5 : PHP_FUNCTION(pcntl_wexitstatus)
     890             : {
     891             : #ifdef WEXITSTATUS
     892             :         zend_long status_word;
     893             :         int int_status_word;
     894             : 
     895           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     896           0 :                return;
     897             :         }
     898             : 
     899           5 :         int_status_word = (int) status_word;
     900           5 :         RETURN_LONG(WEXITSTATUS(int_status_word));
     901             : #else
     902             :         RETURN_FALSE;
     903             : #endif
     904             : }
     905             : /* }}} */
     906             : 
     907             : /* {{{ proto int pcntl_wtermsig(int status)
     908             :    Returns the number of the signal that terminated the process who's status code is passed  */
     909           1 : PHP_FUNCTION(pcntl_wtermsig)
     910             : {
     911             : #ifdef WTERMSIG
     912             :         zend_long status_word;
     913             :         int int_status_word;
     914             : 
     915           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     916           0 :                return;
     917             :         }
     918             : 
     919           1 :         int_status_word = (int) status_word;
     920           1 :         RETURN_LONG(WTERMSIG(int_status_word));
     921             : #else
     922             :         RETURN_FALSE;
     923             : #endif
     924             : }
     925             : /* }}} */
     926             : 
     927             : /* {{{ proto int pcntl_wstopsig(int status)
     928             :    Returns the number of the signal that caused the process to stop who's status code is passed */
     929           1 : PHP_FUNCTION(pcntl_wstopsig)
     930             : {
     931             : #ifdef WSTOPSIG
     932             :         zend_long status_word;
     933             :         int int_status_word;
     934             : 
     935           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
     936           0 :                return;
     937             :         }
     938             : 
     939           1 :         int_status_word = (int) status_word;
     940           1 :         RETURN_LONG(WSTOPSIG(int_status_word));
     941             : #else
     942             :         RETURN_FALSE;
     943             : #endif
     944             : }
     945             : /* }}} */
     946             : 
     947             : /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
     948             :    Executes specified program in current process space as defined by exec(2) */
     949           3 : PHP_FUNCTION(pcntl_exec)
     950             : {
     951           3 :         zval *args = NULL, *envs = NULL;
     952             :         zval *element;
     953             :         HashTable *args_hash, *envs_hash;
     954           3 :         int argc = 0, argi = 0;
     955           3 :         int envc = 0, envi = 0;
     956           3 :         char **argv = NULL, **envp = NULL;
     957             :         char **current_arg, **pair;
     958             :         int pair_length;
     959             :         zend_string *key;
     960             :         char *path;
     961             :         size_t path_len;
     962             :         zend_ulong key_num;
     963             : 
     964           3 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
     965           0 :                 return;
     966             :         }
     967             : 
     968           3 :         if (ZEND_NUM_ARGS() > 1) {
     969             :                 /* Build argument list */
     970           3 :                 args_hash = Z_ARRVAL_P(args);
     971           3 :                 argc = zend_hash_num_elements(args_hash);
     972             : 
     973           3 :                 argv = safe_emalloc((argc + 2), sizeof(char *), 0);
     974           3 :                 *argv = path;
     975           3 :                 current_arg = argv+1;
     976          13 :                 ZEND_HASH_FOREACH_VAL(args_hash, element) {
     977           5 :                         if (argi >= argc) break;
     978           5 :                         convert_to_string_ex(element);
     979           5 :                         *current_arg = Z_STRVAL_P(element);
     980           5 :                         argi++;
     981           5 :                         current_arg++;
     982             :                 } ZEND_HASH_FOREACH_END();
     983           3 :                 *(current_arg) = NULL;
     984             :         } else {
     985           0 :                 argv = emalloc(2 * sizeof(char *));
     986           0 :                 *argv = path;
     987           0 :                 *(argv+1) = NULL;
     988             :         }
     989             : 
     990           3 :         if ( ZEND_NUM_ARGS() == 3 ) {
     991             :                 /* Build environment pair list */
     992           2 :                 envs_hash = Z_ARRVAL_P(envs);
     993           2 :                 envc = zend_hash_num_elements(envs_hash);
     994             : 
     995           2 :                 pair = envp = safe_emalloc((envc + 1), sizeof(char *), 0);
     996          10 :                 ZEND_HASH_FOREACH_KEY_VAL(envs_hash, key_num, key, element) {
     997           4 :                         if (envi >= envc) break;
     998           4 :                         if (!key) {
     999           1 :                                 key = zend_long_to_str(key_num);
    1000             :                         } else {
    1001             :                                 zend_string_addref(key);
    1002             :                         }
    1003             : 
    1004           4 :                         convert_to_string_ex(element);
    1005             : 
    1006             :                         /* Length of element + equal sign + length of key + null */
    1007           4 :                         pair_length = Z_STRLEN_P(element) + ZSTR_LEN(key) + 2;
    1008           4 :                         *pair = emalloc(pair_length);
    1009           4 :                         strlcpy(*pair, ZSTR_VAL(key), ZSTR_LEN(key) + 1);
    1010           4 :                         strlcat(*pair, "=", pair_length);
    1011           4 :                         strlcat(*pair, Z_STRVAL_P(element), pair_length);
    1012             : 
    1013             :                         /* Cleanup */
    1014             :                         zend_string_release_ex(key, 0);
    1015           4 :                         envi++;
    1016           4 :                         pair++;
    1017             :                 } ZEND_HASH_FOREACH_END();
    1018           2 :                 *(pair) = NULL;
    1019             : 
    1020           2 :                 if (execve(path, argv, envp) == -1) {
    1021           1 :                         PCNTL_G(last_error) = errno;
    1022           1 :                         php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
    1023             :                 }
    1024             : 
    1025             :                 /* Cleanup */
    1026           1 :                 for (pair = envp; *pair != NULL; pair++) efree(*pair);
    1027           1 :                 efree(envp);
    1028             :         } else {
    1029             : 
    1030           1 :                 if (execv(path, argv) == -1) {
    1031           0 :                         PCNTL_G(last_error) = errno;
    1032           0 :                         php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
    1033             :                 }
    1034             :         }
    1035             : 
    1036           2 :         efree(argv);
    1037             : 
    1038           1 :         RETURN_FALSE;
    1039             : }
    1040             : /* }}} */
    1041             : 
    1042             : /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
    1043             :    Assigns a system signal handler to a PHP function */
    1044          17 : PHP_FUNCTION(pcntl_signal)
    1045             : {
    1046             :         zval *handle;
    1047             :         zend_long signo;
    1048          17 :         zend_bool restart_syscalls = 1;
    1049             : 
    1050          17 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
    1051           0 :                 return;
    1052             :         }
    1053             : 
    1054          17 :         if (signo < 1 || signo >= NSIG) {
    1055           2 :                 php_error_docref(NULL, E_WARNING, "Invalid signal");
    1056           2 :                 RETURN_FALSE;
    1057             :         }
    1058             : 
    1059          15 :         if (!PCNTL_G(spares)) {
    1060             :                 /* since calling malloc() from within a signal handler is not portable,
    1061             :                  * pre-allocate a few records for recording signals */
    1062             :                 int i;
    1063         660 :                 for (i = 0; i < NSIG; i++) {
    1064             :                         struct php_pcntl_pending_signal *psig;
    1065             : 
    1066         650 :                         psig = emalloc(sizeof(*psig));
    1067         650 :                         psig->next = PCNTL_G(spares);
    1068         650 :                         PCNTL_G(spares) = psig;
    1069             :                 }
    1070             :         }
    1071             : 
    1072             :         /* Special long value case for SIG_DFL and SIG_IGN */
    1073          30 :         if (Z_TYPE_P(handle) == IS_LONG) {
    1074           5 :                 if (Z_LVAL_P(handle) != (zend_long) SIG_DFL && Z_LVAL_P(handle) != (zend_long) SIG_IGN) {
    1075           0 :                         php_error_docref(NULL, E_WARNING, "Invalid value for handle argument specified");
    1076           0 :                         RETURN_FALSE;
    1077             :                 }
    1078           5 :                 if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == (Sigfunc *)SIG_ERR) {
    1079           0 :                         PCNTL_G(last_error) = errno;
    1080           0 :                         php_error_docref(NULL, E_WARNING, "Error assigning signal");
    1081           0 :                         RETURN_FALSE;
    1082             :                 }
    1083           5 :                 zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle);
    1084           5 :                 RETURN_TRUE;
    1085             :         }
    1086             : 
    1087          10 :         if (!zend_is_callable(handle, 0, NULL)) {
    1088           1 :                 zend_string *func_name = zend_get_callable_name(handle);
    1089           1 :                 PCNTL_G(last_error) = EINVAL;
    1090           1 :                 php_error_docref(NULL, E_WARNING, "%s is not a callable function name error", ZSTR_VAL(func_name));
    1091             :                 zend_string_release_ex(func_name, 0);
    1092           1 :                 RETURN_FALSE;
    1093             :         }
    1094             : 
    1095             :         /* Add the function name to our signal table */
    1096           9 :         handle = zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle);
    1097           9 :         Z_TRY_ADDREF_P(handle);
    1098             : 
    1099           9 :         if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == (Sigfunc *)SIG_ERR) {
    1100           0 :                 PCNTL_G(last_error) = errno;
    1101           0 :                 php_error_docref(NULL, E_WARNING, "Error assigning signal");
    1102           0 :                 RETURN_FALSE;
    1103             :         }
    1104           9 :         RETURN_TRUE;
    1105             : }
    1106             : /* }}} */
    1107             : 
    1108             : /* {{{ proto bool pcntl_signal_get_handler(int signo)
    1109             :    Gets signal handler */
    1110           4 : PHP_FUNCTION(pcntl_signal_get_handler)
    1111             : {
    1112             :         zval *prev_handle;
    1113             :         zend_long signo;
    1114             : 
    1115           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &signo) == FAILURE) {
    1116           0 :                 return;
    1117             :         }
    1118             : 
    1119           4 :         if (signo < 1 || signo > 32) {
    1120           0 :                 php_error_docref(NULL, E_WARNING, "Invalid signal");
    1121           0 :                 RETURN_FALSE;
    1122             :         }
    1123             : 
    1124           4 :         if ((prev_handle = zend_hash_index_find(&PCNTL_G(php_signal_table), signo)) != NULL) {
    1125           9 :                 RETURN_ZVAL(prev_handle, 1, 0);
    1126             :         } else {
    1127           1 :                 RETURN_LONG((zend_long)SIG_DFL);
    1128             :         }
    1129             : }
    1130             : 
    1131             : /* {{{ proto bool pcntl_signal_dispatch()
    1132             :    Dispatch signals to signal handlers */
    1133           5 : PHP_FUNCTION(pcntl_signal_dispatch)
    1134             : {
    1135           5 :         pcntl_signal_dispatch();
    1136           5 :         RETURN_TRUE;
    1137             : }
    1138             : /* }}} */
    1139             : 
    1140             : #ifdef HAVE_SIGPROCMASK
    1141             : /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
    1142             :    Examine and change blocked signals */
    1143           9 : PHP_FUNCTION(pcntl_sigprocmask)
    1144             : {
    1145             :         zend_long          how, signo;
    1146           9 :         zval         *user_set, *user_oldset = NULL, *user_signo;
    1147             :         sigset_t      set, oldset;
    1148             : 
    1149           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z", &how, &user_set, &user_oldset) == FAILURE) {
    1150           0 :                 return;
    1151             :         }
    1152             : 
    1153           9 :         if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
    1154           0 :                 PCNTL_G(last_error) = errno;
    1155           0 :                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1156           0 :                 RETURN_FALSE;
    1157             :         }
    1158             : 
    1159          24 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
    1160           8 :                 signo = zval_get_long(user_signo);
    1161           8 :                 if (sigaddset(&set, signo) != 0) {
    1162           1 :                         PCNTL_G(last_error) = errno;
    1163           1 :                         php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1164           1 :                         RETURN_FALSE;
    1165             :                 }
    1166             :         } ZEND_HASH_FOREACH_END();
    1167             : 
    1168           8 :         if (sigprocmask(how, &set, &oldset) != 0) {
    1169           0 :                 PCNTL_G(last_error) = errno;
    1170           0 :                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1171           0 :                 RETURN_FALSE;
    1172             :         }
    1173             : 
    1174           8 :         if (user_oldset != NULL) {
    1175          14 :                 user_oldset = zend_try_array_init(user_oldset);
    1176           7 :                 if (!user_oldset) {
    1177           0 :                         return;
    1178             :                 }
    1179             : 
    1180         455 :                 for (signo = 1; signo < NSIG; ++signo) {
    1181         448 :                         if (sigismember(&oldset, signo) != 1) {
    1182         438 :                                 continue;
    1183             :                         }
    1184          10 :                         add_next_index_long(user_oldset, signo);
    1185             :                 }
    1186             :         }
    1187             : 
    1188           8 :         RETURN_TRUE;
    1189             : }
    1190             : /* }}} */
    1191             : #endif
    1192             : 
    1193             : #ifdef HAVE_STRUCT_SIGINFO_T
    1194             : # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
    1195           5 : static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
    1196             : {
    1197           5 :         zval            *user_set, *user_signo, *user_siginfo = NULL;
    1198           5 :         zend_long             tv_sec = 0, tv_nsec = 0;
    1199             :         sigset_t         set;
    1200             :         int              signo;
    1201             :         siginfo_t        siginfo;
    1202             :         struct timespec  timeout;
    1203             : 
    1204           5 :         if (timedwait) {
    1205           2 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
    1206           0 :                         return;
    1207             :                 }
    1208             :         } else {
    1209           3 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z", &user_set, &user_siginfo) == FAILURE) {
    1210           0 :                         return;
    1211             :                 }
    1212             :         }
    1213             : 
    1214           5 :         if (sigemptyset(&set) != 0) {
    1215           0 :                 PCNTL_G(last_error) = errno;
    1216           0 :                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1217           0 :                 RETURN_FALSE;
    1218             :         }
    1219             : 
    1220          14 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
    1221           5 :                 signo = zval_get_long(user_signo);
    1222           5 :                 if (sigaddset(&set, signo) != 0) {
    1223           1 :                         PCNTL_G(last_error) = errno;
    1224           1 :                         php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1225           1 :                         RETURN_FALSE;
    1226             :                 }
    1227             :         } ZEND_HASH_FOREACH_END();
    1228             : 
    1229           4 :         if (timedwait) {
    1230           2 :                 timeout.tv_sec  = (time_t) tv_sec;
    1231           2 :                 timeout.tv_nsec = tv_nsec;
    1232           2 :                 signo = sigtimedwait(&set, &siginfo, &timeout);
    1233             :         } else {
    1234           2 :                 signo = sigwaitinfo(&set, &siginfo);
    1235             :         }
    1236           4 :         if (signo == -1 && errno != EAGAIN) {
    1237           1 :                 PCNTL_G(last_error) = errno;
    1238           1 :                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
    1239             :         }
    1240             : 
    1241             :         /*
    1242             :          * sigtimedwait and sigwaitinfo can return 0 on success on some
    1243             :          * platforms, e.g. NetBSD
    1244             :          */
    1245           4 :         if (!signo && siginfo.si_signo) {
    1246           0 :                 signo = siginfo.si_signo;
    1247             :         }
    1248           4 :         pcntl_siginfo_to_zval(signo, &siginfo, user_siginfo);
    1249           4 :         RETURN_LONG(signo);
    1250             : }
    1251             : /* }}} */
    1252             : 
    1253             : /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
    1254             :    Synchronously wait for queued signals */
    1255           3 : PHP_FUNCTION(pcntl_sigwaitinfo)
    1256             : {
    1257           3 :         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1258           3 : }
    1259             : /* }}} */
    1260             : 
    1261             : /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
    1262             :    Wait for queued signals */
    1263           2 : PHP_FUNCTION(pcntl_sigtimedwait)
    1264             : {
    1265           2 :         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1266           2 : }
    1267             : /* }}} */
    1268             : # endif
    1269             : 
    1270          10 : static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */
    1271             : {
    1272          10 :         if (signo > 0 && user_siginfo) {
    1273           9 :                 user_siginfo = zend_try_array_init(user_siginfo);
    1274           9 :                 if (!user_siginfo) {
    1275           0 :                         return;
    1276             :                 }
    1277             : 
    1278           9 :                 add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo->si_signo);
    1279           9 :                 add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo->si_errno);
    1280           9 :                 add_assoc_long_ex(user_siginfo, "code",  sizeof("code")-1,  siginfo->si_code);
    1281           9 :                 switch(signo) {
    1282             : #ifdef SIGCHLD
    1283           1 :                         case SIGCHLD:
    1284           1 :                                 add_assoc_long_ex(user_siginfo,   "status", sizeof("status")-1, siginfo->si_status);
    1285             : # ifdef si_utime
    1286           1 :                                 add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime")-1,  siginfo->si_utime);
    1287             : # endif
    1288             : # ifdef si_stime
    1289           1 :                                 add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime")-1,  siginfo->si_stime);
    1290             : # endif
    1291           1 :                                 add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid")-1,    siginfo->si_pid);
    1292           1 :                                 add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid")-1,    siginfo->si_uid);
    1293           1 :                                 break;
    1294           1 :                         case SIGUSR1:
    1295             :                         case SIGUSR2:
    1296           1 :                                 add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid")-1,    siginfo->si_pid);
    1297           1 :                                 add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid")-1,    siginfo->si_uid);
    1298           1 :                                 break;
    1299             : #endif
    1300           0 :                         case SIGILL:
    1301             :                         case SIGFPE:
    1302             :                         case SIGSEGV:
    1303             :                         case SIGBUS:
    1304           0 :                                 add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
    1305           0 :                                 break;
    1306             : #ifdef SIGPOLL
    1307           0 :                         case SIGPOLL:
    1308           0 :                                 add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo->si_band);
    1309             : # ifdef si_fd
    1310           0 :                                 add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd")-1,   siginfo->si_fd);
    1311             : # endif
    1312           0 :                                 break;
    1313             : #endif
    1314             :                 }
    1315             : #if defined(SIGRTMIN) && defined(SIGRTMAX)
    1316           9 :                 if (SIGRTMIN <= signo && signo <= SIGRTMAX) {
    1317           1 :                         add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
    1318           1 :                         add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
    1319             :                 }
    1320             : #endif
    1321             :         }
    1322             : }
    1323             : /* }}} */
    1324             : #endif
    1325             : 
    1326             : #ifdef HAVE_GETPRIORITY
    1327             : /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
    1328             :    Get the priority of any process */
    1329           1 : PHP_FUNCTION(pcntl_getpriority)
    1330             : {
    1331           1 :         zend_long who = PRIO_PROCESS;
    1332           1 :         zend_long pid = getpid();
    1333             :         int pri;
    1334             : 
    1335           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &pid, &who) == FAILURE) {
    1336           0 :                 RETURN_FALSE;
    1337             :         }
    1338             : 
    1339             :         /* needs to be cleared, since any returned value is valid */
    1340           1 :         errno = 0;
    1341             : 
    1342           1 :         pri = getpriority(who, pid);
    1343             : 
    1344           1 :         if (errno) {
    1345           0 :                 PCNTL_G(last_error) = errno;
    1346           0 :                 switch (errno) {
    1347           0 :                         case ESRCH:
    1348           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
    1349           0 :                                 break;
    1350           0 :                         case EINVAL:
    1351           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
    1352           0 :                                 break;
    1353           0 :                         default:
    1354           0 :                                 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
    1355           0 :                                 break;
    1356             :                 }
    1357           0 :                 RETURN_FALSE;
    1358             :         }
    1359             : 
    1360           1 :         RETURN_LONG(pri);
    1361             : }
    1362             : /* }}} */
    1363             : #endif
    1364             : 
    1365             : #ifdef HAVE_SETPRIORITY
    1366             : /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
    1367             :    Change the priority of any process */
    1368           0 : PHP_FUNCTION(pcntl_setpriority)
    1369             : {
    1370           0 :         zend_long who = PRIO_PROCESS;
    1371           0 :         zend_long pid = getpid();
    1372             :         zend_long pri;
    1373             : 
    1374           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|ll", &pri, &pid, &who) == FAILURE) {
    1375           0 :                 RETURN_FALSE;
    1376             :         }
    1377             : 
    1378           0 :         if (setpriority(who, pid, pri)) {
    1379           0 :                 PCNTL_G(last_error) = errno;
    1380           0 :                 switch (errno) {
    1381           0 :                         case ESRCH:
    1382           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
    1383           0 :                                 break;
    1384           0 :                         case EINVAL:
    1385           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
    1386           0 :                                 break;
    1387           0 :                         case EPERM:
    1388           0 :                                 php_error_docref(NULL, 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);
    1389           0 :                                 break;
    1390           0 :                         case EACCES:
    1391           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
    1392           0 :                                 break;
    1393           0 :                         default:
    1394           0 :                                 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
    1395           0 :                                 break;
    1396             :                 }
    1397           0 :                 RETURN_FALSE;
    1398             :         }
    1399             : 
    1400           0 :         RETURN_TRUE;
    1401             : }
    1402             : /* }}} */
    1403             : #endif
    1404             : 
    1405             : /* {{{ proto int pcntl_get_last_error(void)
    1406             :    Retrieve the error number set by the last pcntl function which failed. */
    1407           5 : PHP_FUNCTION(pcntl_get_last_error)
    1408             : {
    1409           5 :         RETURN_LONG(PCNTL_G(last_error));
    1410             : }
    1411             : /* }}} */
    1412             : 
    1413             : /* {{{ proto string pcntl_strerror(int errno)
    1414             :    Retrieve the system error message associated with the given errno. */
    1415           0 : PHP_FUNCTION(pcntl_strerror)
    1416             : {
    1417             :         zend_long error;
    1418             : 
    1419           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error) == FAILURE) {
    1420           0 :                 RETURN_FALSE;
    1421             :         }
    1422             : 
    1423           0 :         RETURN_STRING(strerror(error));
    1424             : }
    1425             : /* }}} */
    1426             : 
    1427             : /* Our custom signal handler that calls the appropriate php_function */
    1428             : #ifdef HAVE_STRUCT_SIGINFO_T
    1429           7 : static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context)
    1430             : #else
    1431             : static void pcntl_signal_handler(int signo)
    1432             : #endif
    1433             : {
    1434             :         struct php_pcntl_pending_signal *psig;
    1435             : 
    1436           7 :         psig = PCNTL_G(spares);
    1437           7 :         if (!psig) {
    1438             :                 /* oops, too many signals for us to track, so we'll forget about this one */
    1439           0 :                 return;
    1440             :         }
    1441           7 :         PCNTL_G(spares) = psig->next;
    1442             : 
    1443           7 :         psig->signo = signo;
    1444           7 :         psig->next = NULL;
    1445             : 
    1446             : #ifdef HAVE_STRUCT_SIGINFO_T
    1447           7 :         psig->siginfo = *siginfo;
    1448             : #endif
    1449             : 
    1450             :         /* the head check is important, as the tick handler cannot atomically clear both
    1451             :          * the head and tail */
    1452           7 :         if (PCNTL_G(head) && PCNTL_G(tail)) {
    1453           0 :                 PCNTL_G(tail)->next = psig;
    1454             :         } else {
    1455           7 :                 PCNTL_G(head) = psig;
    1456             :         }
    1457           7 :         PCNTL_G(tail) = psig;
    1458           7 :         PCNTL_G(pending_signals) = 1;
    1459           7 :         if (PCNTL_G(async_signals)) {
    1460           1 :                 EG(vm_interrupt) = 1;
    1461             :         }
    1462             : }
    1463             : 
    1464          41 : void pcntl_signal_dispatch()
    1465             : {
    1466             :         zval params[2], *handle, retval;
    1467             :         struct php_pcntl_pending_signal *queue, *next;
    1468             :         sigset_t mask;
    1469             :         sigset_t old_mask;
    1470             : 
    1471          41 :         if(!PCNTL_G(pending_signals)) {
    1472          69 :                 return;
    1473             :         }
    1474             : 
    1475             :         /* Mask all signals */
    1476           7 :         sigfillset(&mask);
    1477           7 :         sigprocmask(SIG_BLOCK, &mask, &old_mask);
    1478             : 
    1479             :         /* Bail if the queue is empty or if we are already playing the queue */
    1480           7 :         if (!PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
    1481           1 :                 sigprocmask(SIG_SETMASK, &old_mask, NULL);
    1482           1 :                 return;
    1483             :         }
    1484             : 
    1485             :         /* Prevent reentrant handler calls */
    1486           6 :         PCNTL_G(processing_signal_queue) = 1;
    1487             : 
    1488           6 :         queue = PCNTL_G(head);
    1489           6 :         PCNTL_G(head) = NULL; /* simple stores are atomic */
    1490             : 
    1491             :         /* Allocate */
    1492          18 :         while (queue) {
    1493           6 :                 if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
    1494           6 :                         if (Z_TYPE_P(handle) != IS_LONG) {
    1495           6 :                                 ZVAL_NULL(&retval);
    1496           6 :                                 ZVAL_LONG(&params[0], queue->signo);
    1497             : #ifdef HAVE_STRUCT_SIGINFO_T
    1498           6 :                                 array_init(&params[1]);
    1499           6 :                                 pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, &params[1]);
    1500             : #else
    1501             :                                 ZVAL_NULL(&params[1]);
    1502             : #endif
    1503             : 
    1504             :                                 /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
    1505             :                                 /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
    1506           6 :                                 call_user_function(NULL, NULL, handle, &retval, 2, params);
    1507           6 :                                 zval_ptr_dtor(&retval);
    1508             : #ifdef HAVE_STRUCT_SIGINFO_T
    1509           6 :                                 zval_ptr_dtor(&params[1]);
    1510             : #endif
    1511             :                         }
    1512             :                 }
    1513             : 
    1514           6 :                 next = queue->next;
    1515           6 :                 queue->next = PCNTL_G(spares);
    1516           6 :                 PCNTL_G(spares) = queue;
    1517           6 :                 queue = next;
    1518             :         }
    1519             : 
    1520           6 :         PCNTL_G(pending_signals) = 0;
    1521             : 
    1522             :         /* Re-enable queue */
    1523           6 :         PCNTL_G(processing_signal_queue) = 0;
    1524             : 
    1525             :         /* return signal mask to previous state */
    1526           6 :         sigprocmask(SIG_SETMASK, &old_mask, NULL);
    1527             : }
    1528             : 
    1529             : /* {{{ proto bool pcntl_async_signals([bool on[)
    1530             :    Enable/disable asynchronous signal handling and return the old setting. */
    1531           1 : PHP_FUNCTION(pcntl_async_signals)
    1532             : {
    1533             :         zend_bool on;
    1534             : 
    1535           1 :         if (ZEND_NUM_ARGS() == 0) {
    1536           0 :                 RETURN_BOOL(PCNTL_G(async_signals));
    1537             :         }
    1538           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &on) == FAILURE) {
    1539           0 :                 return;
    1540             :         }
    1541           1 :         RETVAL_BOOL(PCNTL_G(async_signals));
    1542           1 :         PCNTL_G(async_signals) = on;
    1543             : }
    1544             : /* }}} */
    1545             : 
    1546             : #ifdef HAVE_UNSHARE
    1547             : /* {{{ proto bool pcntl_unshare(int flags)
    1548             :    disassociate parts of the process execution context */
    1549           8 : PHP_FUNCTION(pcntl_unshare)
    1550             : {
    1551             :         zend_long flags;
    1552             :         int ret;
    1553             : 
    1554           8 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1555          16 :                 Z_PARAM_LONG(flags)
    1556           8 :         ZEND_PARSE_PARAMETERS_END();
    1557             : 
    1558           8 :         ret = unshare(flags);
    1559           8 :         if (ret == -1) {
    1560           8 :                 PCNTL_G(last_error) = errno;
    1561           8 :                 switch (errno) {
    1562             : #ifdef EINVAL
    1563           6 :                         case EINVAL:
    1564           6 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Invalid flag specified", errno);
    1565           6 :                                 break;
    1566             : #endif
    1567             : #ifdef ENOMEM
    1568           0 :                         case ENOMEM:
    1569           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Insufficient memory for unshare", errno);
    1570           0 :                                 break;
    1571             : #endif
    1572             : #ifdef EPERM
    1573           2 :                         case EPERM:
    1574           2 :                                 php_error_docref(NULL, E_WARNING, "Error %d: No privilege to use these flags", errno);
    1575           2 :                                 break;
    1576             : #endif
    1577             : #ifdef ENOSPC
    1578           0 :                         case ENOSPC:
    1579           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Reached the maximum nesting limit for one of the specified namespaces", errno);
    1580           0 :                                 break;
    1581             : #endif
    1582             : #ifdef EUSERS
    1583           0 :                         case EUSERS:
    1584           0 :                                 php_error_docref(NULL, E_WARNING, "Error %d: Reached the maximum nesting limit for the user namespace", errno);
    1585           0 :                                 break;
    1586             : #endif
    1587           0 :                         default:
    1588           0 :                                 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
    1589           0 :                                 break;
    1590             :                 }
    1591           8 :                 RETURN_FALSE;
    1592             :         }
    1593             : 
    1594           0 :         RETURN_TRUE;
    1595             : }
    1596             : /* }}} */
    1597             : #endif
    1598             : 
    1599           1 : static void pcntl_interrupt_function(zend_execute_data *execute_data)
    1600             : {
    1601           1 :         pcntl_signal_dispatch();
    1602           1 :         if (orig_interrupt_function) {
    1603           0 :                 orig_interrupt_function(execute_data);
    1604             :         }
    1605           1 : }

Generated by: LCOV version 1.10

Generated at Mon, 06 May 2019 17:58:22 +0000 (992 days ago)

Copyright © 2005-2022 The PHP Group
All rights reserved.