public function __construct($name, $pid, Error $error = null) { $this->name = $name; $this->pid = $pid; $this->error = $error; if ($error) { if (__CLASS__ === $error->getClass()) { parent::__construct(sprintf('%s via "%s" fork (%d)', $error->getMessage(), $name, $pid)); } else { parent::__construct(sprintf('%s (%d) thrown in "%s" fork (%d): "%s" (%s:%d)', $error->getClass(), $error->getCode(), $name, $pid, $error->getMessage(), $error->getFile(), $error->getLine())); } } else { parent::__construct(sprintf('An unknown error occurred in "%s" fork (%d)', $name, $pid)); } }
/** * Forks something into another process and returns a deferred object. * @param $callable * @param string $processTitle * @return Fork */ public function fork($callable, $processTitle = null) { if (!is_callable($callable)) { throw new UnexpectedTypeException($callable, 'callable'); } // allow the system to cleanup before forking $this->dispatcher->dispatch(Events::PRE_FORK); if (-1 === ($pid = pcntl_fork())) { throw new ProcessControlException('Unable to fork a new process'); } if (0 === $pid) { if (function_exists('cli_set_process_title') && $processTitle !== null) { cli_set_process_title($processTitle); } // reset the list of child processes $this->forks = array(); // setup the shared memory $shm = $this->factory->createSharedMemory(null, $this->signal); $message = new ExitMessage(); // phone home on shutdown register_shutdown_function(function () use($shm, $message) { $status = null; try { $shm->send($message, false); } catch (\Exception $e) { // probably an error serializing the result $message->setResult(null); $message->setError(Error::fromException($e)); $shm->send($message, false); exit(2); } }); // dispatch an event so the system knows it's in a new process $this->dispatcher->dispatch(Events::POST_FORK); if (!$this->debug) { ob_start(); } try { $result = call_user_func($callable, $shm); $message->setResult($result); $status = is_integer($result) ? $result : 0; } catch (\Exception $e) { $message->setError(Error::fromException($e)); $status = 1; } if (!$this->debug) { $message->setOutput(ob_get_clean()); } exit($status); } // connect to shared memory $shm = $this->factory->createSharedMemory($pid); return $this->forks[$pid] = $this->factory->createFork($pid, $shm, $this->debug); }