Exemplo n.º 1
0
 /**
  * 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;
     }
 }