22declare(strict_types=1);
 
   24namespace pocketmine\thread;
 
   26use pmmp\thread\Thread as NativeThread;
 
   27use pmmp\thread\ThreadSafeArray;
 
   31use 
function error_get_last;
 
   32use 
function error_reporting;
 
   34use 
function register_shutdown_function;
 
   35use 
function set_exception_handler;
 
   37trait CommonThreadPartsTrait{
 
   42    private ?ThreadSafeArray $classLoaders = 
null;
 
   43    protected ?
string $composerAutoloaderPath = 
null;
 
   45    protected bool $isKilled = 
false;
 
   47    private ?ThreadCrashInfo $crashInfo = 
null;
 
   52    public function getClassLoaders() : ?array{
 
   53        return $this->classLoaders !== null ? (array) $this->classLoaders : null;
 
   59    public function setClassLoaders(?array $autoloaders = 
null) : void{
 
   60        $this->composerAutoloaderPath = \
pocketmine\COMPOSER_AUTOLOADER_PATH;
 
   62        if($autoloaders === 
null){
 
   63            $autoloaders = [Server::getInstance()->getLoader()];
 
   66        if($this->classLoaders === 
null){
 
   67            $loaders = $this->classLoaders = 
new ThreadSafeArray();
 
   69            $loaders = $this->classLoaders;
 
   70            foreach($this->classLoaders as $k => $autoloader){
 
   71                unset($this->classLoaders[$k]);
 
   74        foreach($autoloaders as $autoloader){
 
   75            $loaders[] = $autoloader;
 
   84    public function registerClassLoaders() : void{
 
   85        if($this->composerAutoloaderPath !== null){
 
   86            require $this->composerAutoloaderPath;
 
   88        $autoloaders = $this->classLoaders;
 
   89        if($autoloaders !== 
null){
 
   90            foreach($autoloaders as $autoloader){
 
   92                $autoloader->register(
false);
 
   97    public function getCrashInfo() : ?ThreadCrashInfo{
 
  105        if($this->isTerminated() && !$this->isJoined()){
 
  108        return $this->crashInfo;
 
  111    public function start(
int $options = NativeThread::INHERIT_NONE) : bool{
 
  112        ThreadManager::getInstance()->add($this);
 
  114        if($this->getClassLoaders() === 
null){
 
  115            $this->setClassLoaders();
 
  117        return parent::start($options);
 
  120    final public function run() : void{
 
  122        $this->registerClassLoaders();
 
  124        ErrorToExceptionHandler::set();
 
  127        set_exception_handler($this->onUncaughtException(...));
 
  128        register_shutdown_function($this->onShutdown(...));
 
  131        $this->isKilled = 
true;
 
  137    public function quit() : void{
 
  138        $this->isKilled = true;
 
  140        if(!$this->isJoined()){
 
  145        ThreadManager::getInstance()->remove($this);
 
  151    protected function onUncaughtException(\Throwable $e) : void{
 
  152        $this->synchronized(function() use ($e) : void{
 
  153            $this->crashInfo = ThreadCrashInfo::fromThrowable($e, $this->getThreadName());
 
  154            \GlobalLogger::get()->logException($e);
 
  162    protected function onShutdown() : void{
 
  163        $this->synchronized(function() : void{
 
  164            if($this->isTerminated() && $this->crashInfo === null){
 
  165                $last = error_get_last();
 
  166                if($last !== 
null && ($last[
"type"] & CrashDump::FATAL_ERROR_MASK) !== 0){
 
  171                    $crashInfo = ThreadCrashInfo::fromThrowable(
new \RuntimeException(
"Thread crashed without an error - perhaps exit() was called?"), $this->getThreadName());
 
  173                $this->crashInfo = $crashInfo;
 
  177                $lines[] = 
"Fatal error: " . $crashInfo->makePrettyMessage();
 
  178                $lines[] = 
"--- Stack trace ---";
 
  179                foreach($crashInfo->
getTrace() as $frame){
 
  180                    $lines[] = 
"  " . $frame->getPrintableFrame();
 
  182                $lines[] = 
"--- End of fatal error information ---";
 
  183                \GlobalLogger::get()->critical(implode(
"\n", $lines));
 
  191    abstract protected function onRun() : void;
 
  193    public function getThreadName() : string{
 
  194        return (new \ReflectionClass($this))->getShortName();
 
static fromLastErrorInfo(array $info, string $threadName)