]> granicus.if.org Git - php/commitdiff
add rusage support to wait() and waitpid()
authorAntony Dovgal <tony2001@php.net>
Thu, 11 Dec 2014 14:01:55 +0000 (17:01 +0300)
committerJulien Pauli <jpauli@php.net>
Wed, 13 May 2015 13:34:17 +0000 (15:34 +0200)
patch by Anton Stepanenko

ext/pcntl/config.m4
ext/pcntl/pcntl.c
ext/pcntl/tests/pcntl_wait_rusage1.phpt [new file with mode: 0644]
ext/pcntl/tests/pcntl_waitpid_rusage1.phpt [new file with mode: 0644]

index 2ef07f140c0cb92a33294e31016040740f1f9156..70e0aeb0080c3a615c0a3739356132cfe42cc956 100644 (file)
@@ -9,6 +9,6 @@ if test "$PHP_PCNTL" != "no"; then
   AC_CHECK_FUNCS(fork, [ AC_DEFINE(HAVE_FORK,1,[ ]) ], [ AC_MSG_ERROR(pcntl: fork() not supported by this platform) ])
   AC_CHECK_FUNCS(waitpid, [ AC_DEFINE(HAVE_WAITPID,1,[ ]) ], [ AC_MSG_ERROR(pcntl: waitpid() not supported by this platform) ])
   AC_CHECK_FUNCS(sigaction, [ AC_DEFINE(HAVE_SIGACTION,1,[ ]) ], [ AC_MSG_ERROR(pcntl: sigaction() not supported by this platform) ])
-  AC_CHECK_FUNCS([getpriority setpriority wait3 sigprocmask sigwaitinfo sigtimedwait])
+  AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigprocmask sigwaitinfo sigtimedwait])
   PHP_NEW_EXTENSION(pcntl, pcntl.c php_signal.c, $ext_shared, cli)
 fi
index 7e7513977139568928ce57926297d2cbf8e985ef..f152ad88146160e06627b703060779b93d04a5cf 100644 (file)
@@ -57,11 +57,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
        ZEND_ARG_INFO(0, pid)
        ZEND_ARG_INFO(1, status)
        ZEND_ARG_INFO(0, options)
+       ZEND_ARG_INFO(1, rusage)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
        ZEND_ARG_INFO(1, status)
        ZEND_ARG_INFO(0, options)
+       ZEND_ARG_INFO(1, rusage)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
@@ -577,54 +579,128 @@ PHP_FUNCTION(pcntl_alarm)
 }
 /* }}} */
 
-/* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
+#define PHP_RUSAGE_PARA(from, to, field) \
+       add_assoc_long(to, #field, from.field)
+#if !defined(_OSD_POSIX) && !defined(__BEOS__) /* BS2000 has only a few fields in the rusage struct */
+       #define PHP_RUSAGE_SPECIAL(from, to) \
+               PHP_RUSAGE_PARA(from, to, ru_oublock); \
+               PHP_RUSAGE_PARA(from, to, ru_inblock); \
+               PHP_RUSAGE_PARA(from, to, ru_msgsnd); \
+               PHP_RUSAGE_PARA(from, to, ru_msgrcv); \
+               PHP_RUSAGE_PARA(from, to, ru_maxrss); \
+               PHP_RUSAGE_PARA(from, to, ru_ixrss); \
+               PHP_RUSAGE_PARA(from, to, ru_idrss); \
+               PHP_RUSAGE_PARA(from, to, ru_minflt); \
+               PHP_RUSAGE_PARA(from, to, ru_majflt); \
+               PHP_RUSAGE_PARA(from, to, ru_nsignals); \
+               PHP_RUSAGE_PARA(from, to, ru_nvcsw); \
+               PHP_RUSAGE_PARA(from, to, ru_nivcsw); \
+               PHP_RUSAGE_PARA(from, to, ru_nswap);
+#else /*_OSD_POSIX*/
+       #define PHP_RUSAGE_SPECIAL(from, to)
+#endif
+
+#define PHP_RUSAGE_COMMON(from ,to) \
+       PHP_RUSAGE_PARA(from, to, ru_utime.tv_usec); \
+       PHP_RUSAGE_PARA(from, to, ru_utime.tv_sec); \
+       PHP_RUSAGE_PARA(from, to, ru_stime.tv_usec); \
+       PHP_RUSAGE_PARA(from, to, ru_stime.tv_sec);
+
+#define PHP_RUSAGE_TO_ARRAY(from, to) \
+       if (to) { \
+               PHP_RUSAGE_SPECIAL(from, to) \
+               PHP_RUSAGE_COMMON(from, to); \
+       }
+
+/* {{{ proto int pcntl_waitpid(int pid, int &status, int options, array &$rusage)
    Waits on or returns the status of a forked child as defined by the waitpid() system call */
 PHP_FUNCTION(pcntl_waitpid)
 {
        zend_long pid, options = 0;
-       zval *z_status = NULL;
+       zval *z_status = NULL, *z_rusage = NULL;
        int status;
        pid_t child_id;
+#ifdef HAVE_WAIT4
+       struct rusage rusage;
+#endif
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/|l", &pid, &z_status, &options) == FAILURE)
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/|lz/", &pid, &z_status, &options, &z_rusage) == FAILURE)
                return;
 
        convert_to_long_ex(z_status);
 
        status = Z_LVAL_P(z_status);
 
+#ifdef HAVE_WAIT4
+       if (z_rusage) {
+               if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
+                       zval_dtor(z_rusage);
+                       array_init(z_rusage);
+               } else {
+                       zend_hash_clean(Z_ARRVAL_P(z_rusage));
+               }
+       }
+
+       if (z_rusage) {
+               memset(&rusage, 0, sizeof(struct rusage));
+               child_id = wait4((pid_t) pid, &status, options, &rusage);
+       } else {
+               child_id = waitpid((pid_t) pid, &status, options);
+       }
+#else
        child_id = waitpid((pid_t) pid, &status, options);
+#endif
 
        if (child_id < 0) {
                PCNTL_G(last_error) = errno;
        }
 
+#ifdef HAVE_WAIT4
+       if (child_id > 0) {
+               PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
+       }
+#endif
+
        Z_LVAL_P(z_status) = status;
 
        RETURN_LONG((zend_long) child_id);
 }
 /* }}} */
 
-/* {{{ proto int pcntl_wait(int &status)
+/* {{{ proto int pcntl_wait(int &status, int $options, array &$rusage)
    Waits on or returns the status of a forked child as defined by the waitpid() system call */
 PHP_FUNCTION(pcntl_wait)
 {
        zend_long options = 0;
-       zval *z_status = NULL;
+       zval *z_status = NULL, *z_rusage = NULL;
        int status;
        pid_t child_id;
+#ifdef HAVE_WAIT3
+       struct rusage rusage;
+#endif
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/|l", &z_status, &options) == FAILURE)
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/|lz/", &z_status, &options, &z_rusage) == FAILURE)
                return;
 
        convert_to_long_ex(z_status);
 
        status = Z_LVAL_P(z_status);
 #ifdef HAVE_WAIT3
-       if(options) {
-               child_id = wait3(&status, options, NULL);
+       if (z_rusage) {
+               if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
+                       zval_dtor(z_rusage);
+                       array_init(z_rusage);
+               } else {
+                       zend_hash_clean(Z_ARRVAL_P(z_rusage));
+               }
        }
-       else {
+
+       if (z_rusage) {
+               memset(&rusage, 0, sizeof(struct rusage));
+               child_id = wait3(&status, options, &rusage);
+       } else if (options) {
+               child_id = wait3(&status, options, NULL);
+       } else {
                child_id = wait(&status);
        }
 #else
@@ -634,13 +710,23 @@ PHP_FUNCTION(pcntl_wait)
                PCNTL_G(last_error) = errno;
        }
 
+#ifdef HAVE_WAIT3
+       if (child_id > 0) {
+               PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
+       }
+#endif
        Z_LVAL_P(z_status) = status;
 
        RETURN_LONG((zend_long) child_id);
 }
 /* }}} */
 
-/* {{{ proto bool pcntl_wifexited(int status)
+#undef PHP_RUSAGE_PARA
+#undef PHP_RUSAGE_SPECIAL
+#undef PHP_RUSAGE_COMMON
+#undef PHP_RUSAGE_TO_ARRAY
+
+/* {{{ proto bool pcntl_wifexited(int status) 
    Returns true if the child status code represents a successful exit */
 PHP_FUNCTION(pcntl_wifexited)
 {
diff --git a/ext/pcntl/tests/pcntl_wait_rusage1.phpt b/ext/pcntl/tests/pcntl_wait_rusage1.phpt
new file mode 100644 (file)
index 0000000..9e95f00
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+pcntl_wait() and rusage
+--SKIPIF--
+<?php if (!extension_loaded("pcntl")) print "skip"; ?>
+<?php if (!extension_loaded("posix")) die("skip posix extension not available"); ?>
+--FILE--
+<?php
+$pid = pcntl_fork();
+if ($pid == 1) {
+       die("failed");
+} else if ($pid) {
+       $status = 0;
+       var_dump(pcntl_wait($status, WUNTRACED, $rusage));
+       var_dump($rusage['ru_utime.tv_sec']);
+       var_dump($rusage['ru_utime.tv_usec']);
+
+       posix_kill($pid, SIGCONT);
+
+       $rusage = array(1,2,3);
+       pcntl_wait($status, WUNTRACED, $rusage);
+       var_dump($rusage['ru_utime.tv_sec']);
+       var_dump($rusage['ru_utime.tv_usec']);
+
+       $rusage = "string";
+       pcntl_wait($status, 0, $rusage);
+       var_dump(gettype($rusage));
+       var_dump(count($rusage));
+       
+       $rusage = new stdClass;
+       pcntl_wait($status, 0, $rusage);
+       var_dump(gettype($rusage));
+       var_dump(count($rusage));
+
+       echo "END\n";
+} else {
+       posix_kill(posix_getpid(), SIGSTOP);
+       exit(42);
+}
+?>
+--EXPECTF--
+int(%d)
+int(%d)
+int(%d)
+int(%d)
+int(%d)
+string(5) "array"
+int(0)
+string(5) "array"
+int(0)
+END
diff --git a/ext/pcntl/tests/pcntl_waitpid_rusage1.phpt b/ext/pcntl/tests/pcntl_waitpid_rusage1.phpt
new file mode 100644 (file)
index 0000000..b5c9aae
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+pcntl_waitpid() and rusage
+--SKIPIF--
+<?php if (!extension_loaded("pcntl")) print "skip"; ?>
+<?php if (!extension_loaded("posix")) die("skip posix extension not available"); ?>
+--FILE--
+<?php
+$pid = pcntl_fork();
+if ($pid == 1) {
+       die("failed");
+} else if ($pid) {
+       $status = 0;
+       var_dump(pcntl_waitpid($pid, $status, WUNTRACED, $rusage));
+       var_dump($rusage['ru_utime.tv_sec']);
+       var_dump($rusage['ru_utime.tv_usec']);
+
+       posix_kill($pid, SIGCONT);
+
+       $rusage = array(1,2,3);
+       pcntl_waitpid($pid, $status, WUNTRACED, $rusage);
+       var_dump($rusage['ru_utime.tv_sec']);
+       var_dump($rusage['ru_utime.tv_usec']);
+
+       $rusage = "string";
+       pcntl_waitpid($pid, $status, 0, $rusage);
+       var_dump(gettype($rusage));
+       var_dump(count($rusage));
+       
+       $rusage = new stdClass;
+       pcntl_waitpid($pid, $status, 0, $rusage);
+       var_dump(gettype($rusage));
+       var_dump(count($rusage));
+
+       echo "END\n";
+} else {
+       posix_kill(posix_getpid(), SIGSTOP);
+       exit(42);
+}
+?>
+--EXPECTF--
+int(%d)
+int(%d)
+int(%d)
+int(%d)
+int(%d)
+string(5) "array"
+int(0)
+string(5) "array"
+int(0)
+END