ZF-8176: $parent->isRunning() never updated after child proccess fork

Description

This code I found in reference manual will never work, cose after fork child process will never change _isRunning variable in parent process and $process1->isRunning() will always return true even after child process stop running.

==================

class MyProcess extends ZendX_Console_Process_Unix { protected function _run() { for ($i = 0; $i < 10; $i++) { // Doing something really important which can't wait: sleeping sleep(1); } } }

// This part should last about 10 seconds, not 20. $process1 = new MyProcess(); $process1->start();

$process2 = new MyProcess(); $process2->start();

while ($process1->isRunning() && $process2->isRunning()) { sleep(1); }

echo 'All processes completed';

Comments

I seem to be having the same problem, the processes run forever. I tried the ZendX_Console_Process_UnixTest::testParallel() code and it failed.

Same problem here!

This will fix the problem on OSX's WAITPID behavior (Linux not yet tested):

public function isRunning() {
$this->_isRunning = (0 == pcntl_waitpid($this->_pid, $status, WNOHANG)); return $this->_isRunning; }

The isRunning() fix seems to works under Linux too. I've tested under Debian Lenny.

Here is another fix.

shmop_read returns a string and therefore it's ($okay === "0") instead of === 0.

/**
 * Wait for IPC Semaphore
 * 
 * @return void
 */
private function _waitForIpcSemaphore()
{
    while (true) {
        $okay = shmop_read($this->_internalSemKey, 0, 1);
        if ($okay === "0") {
            break;
        }
        usleep(10);
    }
}

Looks like the class is based on PHP_Fork from PEAR. Really needs some redesign.

I've had the the same problem, it seems that the isRunning is only good for checking, whether the process started or not. So I implemented an isFinished method with a getFinished and _setFinished. isFinished() returns whether or not the process is finished running, getFinished returns when was the _setFinished called, so it can be used for measuring the execution time.

I'm gonna attach the patch.

Tyrael

isFinished, getFinished, _setFinished

sorry, I missed something from the patch. I wanted to set the actual time in the _setFinished method, so the "true" should be "time()" there.

Tyrael