/** * Will create PGP Fatal on remote thread within loop * @throws Exception */ public function emulateFatalOnRemoteLoop() { if ($this->isExternal()) { $this->loop->nextTick(function () { $this->emulateFatal(); }); } else { $this->callOnChild(__FUNCTION__, func_get_args()); } }
public function fork() { $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); $pid = pcntl_fork(); $this->isRunning = true; if ($pid <= -1) { $this->isRunning = false; throw new \RuntimeException("Unable to fork child: " . pcntl_strerror(pcntl_get_last_error())); } elseif ($pid === 0) { //child proc try { $this->isExternal = true; $this->childPid = posix_getpid(); set_error_handler(array(ThreadConfig::GetErrorHandler(), 'OnUncaughtErrorTriggered')); register_shutdown_function(function () { //catch fatal on some cases $fatalErrorCodes = array(E_ERROR, E_COMPILE_ERROR, E_PARSE); $error = error_get_last(); if (is_array($error) && isset($error['type']) && in_array($error['type'], $fatalErrorCodes)) { $exception = new SerializableFatalException($error['message'], $error['file'], $error['line'], $error['type']); if ($this->messageInProgress instanceof AsyncMessage) { //mark as error and send back to parent $this->messageInProgress->Error($exception); $this->connection->writeSync($this->messageInProgress); } else { $message = new AsyncMessage(array(), true); $message->setIsOneWay(true); $message->Error($exception); $this->connection->writeSync($message); } } }); $this->loop = $this->loop->afterForkChild(); fclose($sockets[1]); $this->socket = $sockets[0]; $this->connection = new ThreadConnection($this->loop, $this->socket); $this->connection->on('message', function ($connection, AsyncMessage $message) { $this->AttachMessage($message); }); $this->loop->nextTick(function () { $this->messageHandler->InitializeExternal($this); }); $this->loop->run(); } catch (\Exception $e) { $handler = ThreadConfig::GetErrorHandler(); $result = @$handler->OnUncaughtException($e); //redirect exception to client. if ($this->messageInProgress instanceof AsyncMessage) { //mark as error and send back to parent $this->messageInProgress->Error($result); $this->connection->writeSync($this->messageInProgress); } else { $message = new AsyncMessage(array(), true); $message->setIsOneWay(true); $message->Error($result); $this->connection->writeSync($message); } //no more chance to handle here :-( } exit; } else { // parent fclose($sockets[0]); $this->socket = $sockets[1]; $this->getLoop()->afterForkParent(); $this->connection = new ThreadConnection($this->loop, $this->socket); $this->connection->on('message', function ($connection, AsyncMessage $message) { $this->AttachMessage($message); }); //keep an eye on the thread $this->pidCollector = $this->getLoop()->addPeriodicTimer(5, function (TimerInterface $timer) { $this->waitForCompletion($timer); }); $this->childPid = $pid; } }