Allow thread errors and their traces to be properly recorded in crashdumps (#5910)

until now, any thread crash would show as a generic crash since we aren't able to get the trace from the crashed thread directly. This uses some dirty tricks to export a partially serialized stack trace to the main thread, where it can be written into a crashdump.
This enables us to see proper crash information for async tasks in the crash archive (finally!!!) as well as being able to capture RakLib errors properly.
This commit is contained in:
Dylan T
2023-07-26 16:26:03 +01:00
committed by GitHub
parent bbdcab7277
commit 82a5ea9ed3
15 changed files with 329 additions and 162 deletions

View File

@ -26,6 +26,7 @@ namespace pocketmine\scheduler;
use pmmp\thread\Thread as NativeThread;
use pocketmine\snooze\SleeperHandler;
use pocketmine\thread\log\ThreadSafeLogger;
use pocketmine\thread\ThreadCrashException;
use pocketmine\thread\ThreadSafeClassLoader;
use pocketmine\timings\Timings;
use pocketmine\utils\AssumptionFailedError;
@ -215,12 +216,17 @@ class AsyncPool{
}
}
}
if($crashedTask !== null){
$message = "Worker $workerId crashed while running task " . get_class($crashedTask) . "#" . spl_object_id($crashedTask);
$info = $entry->worker->getCrashInfo();
if($info !== null){
if($crashedTask !== null){
$message = "Worker $workerId crashed while running task " . get_class($crashedTask) . "#" . spl_object_id($crashedTask);
}else{
$message = "Worker $workerId crashed while doing unknown work";
}
throw new ThreadCrashException($message, $info);
}else{
$message = "Worker $workerId crashed for unknown reason";
throw new \RuntimeException("Worker $workerId crashed for unknown reason");
}
throw new \RuntimeException($message);
}
}

View File

@ -31,7 +31,6 @@ use pocketmine\thread\Worker;
use pocketmine\utils\AssumptionFailedError;
use function gc_enable;
use function ini_set;
use function set_exception_handler;
class AsyncWorker extends Worker{
/** @var mixed[] */
@ -68,20 +67,17 @@ class AsyncWorker extends Worker{
}
$this->saveToThreadStore(self::TLS_KEY_NOTIFIER, $this->sleeperEntry->createNotifier());
}
set_exception_handler(function(\Throwable $e){
$this->logger->logException($e);
});
protected function onUncaughtException(\Throwable $e) : void{
parent::onUncaughtException($e);
$this->logger->logException($e);
}
public function getLogger() : ThreadSafeLogger{
return $this->logger;
}
public function handleException(\Throwable $e) : void{
$this->logger->logException($e);
}
public function getThreadName() : string{
return "AsyncWorker#" . $this->id;
}