function = $function; $this->args = $args; $this->socket = $socket; } /** * Runs the thread code and the initialized function. * * @codeCoverageIgnore Only executed in thread. */ public function run() { /* First thing we need to do is re-initialize the class autoloader. If * we don't do this first, any object of a class that was loaded after * the thread started will just be garbage data and unserializable * values (like resources) will be lost. This happens even with * thread-safe objects. */ foreach (get_declared_classes() as $className) { if (strpos($className, 'ComposerAutoloaderInit') === 0) { // Calling getLoader() will register the class loader for us $className::getLoader(); break; } } $loop = Loop\create(false); // Disable signals in thread. Loop\loop($loop); // At this point, the thread environment has been prepared so begin using the thread. $channel = new Channel(new DuplexStream($this->socket)); $coroutine = new Coroutine($this->execute($channel)); $coroutine->done(); $timer = $loop->timer(self::KILL_CHECK_FREQUENCY, true, function () use ($loop, $coroutine, $channel) { if ($this->killed) { $loop->stop(); } }); $timer->unreference(); $loop->run(); } /** * Sets a local variable to true so the running event loop can check for a kill signal. */ public function kill() { $this->killed = true; parent::kill(); } /** * @coroutine * * @param \Icicle\Concurrent\Sync\ChannelInterface $channel * * @return \Generator * * @resolve int * * @codeCoverageIgnore Only executed in thread. */ private function execute(ChannelInterface $channel) { $executor = new Executor($this, $channel); try { if ($this->function instanceof \Closure) { $function = $this->function->bindTo($executor, Executor::class); } if (empty($function)) { $function = $this->function; } $result = new ExitSuccess(yield call_user_func_array($function, $this->args)); } catch (\Exception $exception) { $result = new ExitFailure($exception); } yield $channel->send($result); } }