Exemplo n.º 1
0
 /**
  * Closes the stream resource provided, the open process handle, and stdin.
  *
  * @param resource $resource
  */
 private function close($resource)
 {
     if (is_resource($resource)) {
         fclose($resource);
     }
     if (is_resource($this->process)) {
         proc_close($this->process);
         $this->process = null;
     }
     $this->stdin->close();
 }
Exemplo n.º 2
0
 /**
  * {@inheritdoc}
  *
  * @param float|int $timeout Timeout for poll and await if a read or write was pending.
  */
 public function rebind(float $timeout = 0)
 {
     $this->readable->rebind($timeout);
     $this->writable->rebind($timeout);
 }
Exemplo n.º 3
0
    /**
     * @throws \Icicle\Concurrent\Exception\StatusError If the process is already running.
     */
    public function start()
    {
        if (null !== $this->promise) {
            throw new StatusError('The process has already been started.');
        }

        $fd = [
            ['pipe', 'r'], // stdin
            ['pipe', 'w'], // stdout
            ['pipe', 'a'], // stderr
            ['pipe', 'w'], // exit code pipe
        ];

        $nd = 0 === strncasecmp(PHP_OS, 'WIN', 3) ? 'NUL' : '/dev/null';

        $command = sprintf('(%s) 3>%s; code=$?; echo $code >&3; exit $code', $this->command, $nd);

        $this->process = proc_open($command, $fd, $pipes, $this->cwd ?: null, $this->env ?: null, $this->options);

        if (!is_resource($this->process)) {
            throw new ProcessException('Could not start process.');
        }

        $this->oid = getmypid();

        $status = proc_get_status($this->process);

        if (!$status) {
            proc_close($this->process);
            $this->process = null;
            throw new ProcessException('Could not get process status.');
        }

        $this->pid = $status['pid'];

        $this->stdin = new WritablePipe($pipes[0]);
        $this->stdout = new ReadablePipe($pipes[1]);
        $this->stderr = new ReadablePipe($pipes[2]);

        $stream = $pipes[3];
        stream_set_blocking($stream, 0);

        $this->promise = new Promise(function (callable $resolve, callable $reject) use ($stream) {
            $this->poll = Loop\poll($stream, function ($resource) use ($resolve, $reject) {
                if (feof($resource)) {
                    $reject(new ProcessException('Process ended unexpectedly.'));
                } else {
                    $code = fread($resource, 1);

                    if (!strlen($code) || !is_numeric($code)) {
                        $reject(new ProcessException('Process ended without providing a status code.'));
                    } else {
                        $resolve((int) $code);
                    }
                }

                fclose($resource);

                if (is_resource($this->process)) {
                    proc_close($this->process);
                    $this->process = null;
                }

                $this->stdin->close();
                $this->poll->free();
            });

            $this->poll->unreference();
            $this->poll->listen();
        });
    }