From e0630fbb256401bb392229eda9f8b8b0a220d034 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 20 May 2023 01:29:26 +0100 Subject: [PATCH] pmmpthread support --- .github/workflows/main.yml | 10 +-- composer.json | 8 +- composer.lock | 79 ++++++++++--------- phpstan.neon.dist | 2 +- src/PocketMine.php | 2 +- src/Server.php | 4 +- src/console/ConsoleReaderChildProcess.php | 15 ++-- .../mcpe/raklib/PthreadsChannelReader.php | 5 +- .../mcpe/raklib/PthreadsChannelWriter.php | 5 +- src/network/mcpe/raklib/RakLibInterface.php | 9 ++- src/network/mcpe/raklib/RakLibServer.php | 19 ++--- .../SnoozeAwarePthreadsChannelWriter.php | 5 +- src/scheduler/AsyncPool.php | 9 ++- src/scheduler/AsyncTask.php | 20 +++-- src/scheduler/AsyncWorker.php | 11 +-- src/scheduler/DumpWorkerMemoryTask.php | 10 ++- src/thread/CommonThreadPartsTrait.php | 12 +-- src/thread/NonThreadSafeValue.php | 3 +- src/thread/Thread.php | 6 +- src/thread/ThreadManager.php | 10 ++- src/thread/Worker.php | 7 +- src/utils/MainLogger.php | 14 ++-- src/utils/MainLoggerThread.php | 10 ++- .../stubs/{pthreads.stub => pmmpthread.stub} | 10 ++- 24 files changed, 159 insertions(+), 126 deletions(-) rename tests/phpstan/stubs/{pthreads.stub => pmmpthread.stub} (70%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa0eccf60..b4a884882 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Build and prepare PHP cache - uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 + uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5 with: php-version: ${{ matrix.php }} install-path: "./bin" @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v3 - name: Setup PHP - uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 + uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5 with: php-version: ${{ matrix.php }} install-path: "./bin" @@ -77,7 +77,7 @@ jobs: - uses: actions/checkout@v3 - name: Setup PHP - uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 + uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5 with: php-version: ${{ matrix.php }} install-path: "./bin" @@ -118,7 +118,7 @@ jobs: submodules: true - name: Setup PHP - uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 + uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5 with: php-version: ${{ matrix.php }} install-path: "./bin" @@ -157,7 +157,7 @@ jobs: - uses: actions/checkout@v3 - name: Setup PHP - uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 + uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5 with: php-version: ${{ matrix.php }} install-path: "./bin" diff --git a/composer.json b/composer.json index fb0748573..63d5b0d00 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-openssl": "*", "ext-pcre": "*", "ext-phar": "*", - "ext-pthreads": "^5.1", + "ext-pmmpthread": "^6.0", "ext-reflection": "*", "ext-simplexml": "*", "ext-sockets": "*", @@ -40,17 +40,17 @@ "pocketmine/bedrock-protocol": "~21.0.0+bedrock-1.19.80", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", - "pocketmine/classloader": "^0.3.0", + "pocketmine/classloader": "dev-stable", "pocketmine/color": "^0.3.0", "pocketmine/errorhandler": "^0.6.0", "pocketmine/locale-data": "~2.19.0", "pocketmine/log": "^0.4.0", - "pocketmine/log-pthreads": "^0.5.0", + "pocketmine/log-pthreads": "dev-stable", "pocketmine/math": "^0.4.0", "pocketmine/nbt": "^0.3.2", "pocketmine/raklib": "^0.15.0", "pocketmine/raklib-ipc": "^0.2.0", - "pocketmine/snooze": "^0.4.0", + "pocketmine/snooze": "dev-master", "ramsey/uuid": "^4.1", "symfony/filesystem": "^5.4" }, diff --git a/composer.lock b/composer.lock index cdcb19063..4b6e1622f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8c09886bd34e74a61c3ea1ee2be3b2e9", + "content-hash": "507c2a45350440a7717ed089190fe4f0", "packages": [ { "name": "adhocore/json-comment", @@ -466,32 +466,33 @@ }, { "name": "pocketmine/classloader", - "version": "0.3.0", + "version": "dev-stable", "source": { "type": "git", "url": "https://github.com/pmmp/ClassLoader.git", - "reference": "407caf521186ec1f03024f39031cc681ad491026" + "reference": "e15c9b4d310581d2d2c9bf2794869cb940e011e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/407caf521186ec1f03024f39031cc681ad491026", - "reference": "407caf521186ec1f03024f39031cc681ad491026", + "url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/e15c9b4d310581d2d2c9bf2794869cb940e011e1", + "reference": "e15c9b4d310581d2d2c9bf2794869cb940e011e1", "shasum": "" }, "require": { - "ext-pthreads": "^5.0", + "ext-pmmpthread": "^6.0", "ext-reflection": "*", - "php": "^8.0" + "php": "^8.1" }, "conflict": { "pocketmine/spl": "<0.4" }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.9.4", + "phpstan/phpstan": "1.10.15", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5" }, + "default-branch": true, "type": "library", "autoload": { "classmap": [ @@ -505,9 +506,9 @@ "description": "Ad-hoc autoloading components used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/ClassLoader/issues", - "source": "https://github.com/pmmp/ClassLoader/tree/0.3.0" + "source": "https://github.com/pmmp/ClassLoader/tree/stable" }, - "time": "2023-01-23T19:46:53+00:00" + "time": "2023-05-19T23:39:02+00:00" }, { "name": "pocketmine/color", @@ -652,21 +653,21 @@ }, { "name": "pocketmine/log-pthreads", - "version": "0.5.0", + "version": "dev-stable", "source": { "type": "git", "url": "https://github.com/pmmp/LogPthreads.git", - "reference": "0ecfea6dcfc9a9f5c86e126ac1661732de5c5666" + "reference": "bb3b5395042d12ec0d7ad5c855fd86eaf12869d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/0ecfea6dcfc9a9f5c86e126ac1661732de5c5666", - "reference": "0ecfea6dcfc9a9f5c86e126ac1661732de5c5666", + "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/bb3b5395042d12ec0d7ad5c855fd86eaf12869d3", + "reference": "bb3b5395042d12ec0d7ad5c855fd86eaf12869d3", "shasum": "" }, "require": { - "ext-pthreads": "^5.0", - "php": "^8.0", + "ext-pmmpthread": "^6.0", + "php": "^8.1", "pocketmine/log": "^0.4.0" }, "conflict": { @@ -674,9 +675,10 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.8.11", + "phpstan/phpstan": "1.10.3", "phpstan/phpstan-strict-rules": "^1.0" }, + "default-branch": true, "type": "library", "autoload": { "classmap": [ @@ -690,9 +692,9 @@ "description": "Logging components specialized for pthreads used by PocketMine-MP and related projects", "support": { "issues": "https://github.com/pmmp/LogPthreads/issues", - "source": "https://github.com/pmmp/LogPthreads/tree/0.5.0" + "source": "https://github.com/pmmp/LogPthreads/tree/stable" }, - "time": "2023-01-23T19:52:12+00:00" + "time": "2023-05-19T23:38:36+00:00" }, { "name": "pocketmine/math", @@ -863,27 +865,28 @@ }, { "name": "pocketmine/snooze", - "version": "0.4.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/pmmp/Snooze.git", - "reference": "6b1d6cc645d674590ff9be2438ac00032f9ee292" + "reference": "3207a201cbb10eebb4a96749678f7adef216bb71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Snooze/zipball/6b1d6cc645d674590ff9be2438ac00032f9ee292", - "reference": "6b1d6cc645d674590ff9be2438ac00032f9ee292", + "url": "https://api.github.com/repos/pmmp/Snooze/zipball/3207a201cbb10eebb4a96749678f7adef216bb71", + "reference": "3207a201cbb10eebb4a96749678f7adef216bb71", "shasum": "" }, "require": { - "ext-pthreads": "^5.0", - "php-64bit": "^8.0" + "ext-pmmpthread": "^6.0", + "php-64bit": "^8.1" }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.9.14", + "phpstan/phpstan": "1.10.3", "phpstan/phpstan-strict-rules": "^1.0" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -897,9 +900,9 @@ "description": "Thread notification management library for code using the pthreads extension", "support": { "issues": "https://github.com/pmmp/Snooze/issues", - "source": "https://github.com/pmmp/Snooze/tree/0.4.0" + "source": "https://github.com/pmmp/Snooze/tree/master" }, - "time": "2023-01-23T19:43:19+00:00" + "time": "2023-05-19T23:38:19+00:00" }, { "name": "ramsey/collection", @@ -1527,16 +1530,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -1577,9 +1580,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phar-io/manifest", @@ -3293,7 +3296,11 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "pocketmine/classloader": 20, + "pocketmine/log-pthreads": 20, + "pocketmine/snooze": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -3314,7 +3321,7 @@ "ext-openssl": "*", "ext-pcre": "*", "ext-phar": "*", - "ext-pthreads": "^5.1", + "ext-pmmpthread": "^6.0", "ext-reflection": "*", "ext-simplexml": "*", "ext-sockets": "*", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 16b692ec9..b3aeaf4f6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -44,7 +44,7 @@ parameters: - tests/phpstan/stubs/JsonMapper.stub - tests/phpstan/stubs/leveldb.stub - tests/phpstan/stubs/phpasn1.stub - - tests/phpstan/stubs/pthreads.stub + - tests/phpstan/stubs/pmmpthread.stub reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings staticReflectionClassNamePatterns: - "#^COM$#" diff --git a/src/PocketMine.php b/src/PocketMine.php index 8bdb55b0d..c085fa19c 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -338,7 +338,7 @@ JIT_WARNING $logger->info("Stopping other threads"); $killer = new ServerKiller(8); - $killer->start(PTHREADS_INHERIT_NONE); + $killer->start(); usleep(10000); //Fixes ServerKiller not being able to start on single-core machines if(ThreadManager::getInstance()->stopAll() > 0){ diff --git a/src/Server.php b/src/Server.php index c19553a88..1262bc00e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -417,7 +417,7 @@ class Server{ return $this->autoloader; } - public function getLogger() : \AttachableThreadedLogger{ + public function getLogger() : \AttachableThreadSafeLogger{ return $this->logger; } @@ -760,7 +760,7 @@ class Server{ public function __construct( private \DynamicClassLoader $autoloader, - private \AttachableThreadedLogger $logger, + private \AttachableThreadSafeLogger $logger, string $dataPath, string $pluginPath ){ diff --git a/src/console/ConsoleReaderChildProcess.php b/src/console/ConsoleReaderChildProcess.php index 3dd2c24c2..c37aaa8c9 100644 --- a/src/console/ConsoleReaderChildProcess.php +++ b/src/console/ConsoleReaderChildProcess.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\console; +use pmmp\thread\Thread as NativeThread; +use pmmp\thread\ThreadSafeArray; use pocketmine\utils\Process; use function cli_set_process_title; use function count; @@ -30,7 +32,6 @@ use function dirname; use function feof; use function fwrite; use function stream_socket_client; -use const PTHREADS_INHERIT_NONE; require dirname(__DIR__, 2) . '/vendor/autoload.php'; @@ -46,14 +47,14 @@ if($socket === false){ throw new \RuntimeException("Failed to connect to server process ($errCode): $errMessage"); } -/** @phpstan-var \ThreadedArray $channel */ -$channel = new \ThreadedArray(); -$thread = new class($channel) extends \Thread{ +/** @phpstan-var ThreadSafeArray $channel */ +$channel = new ThreadSafeArray(); +$thread = new class($channel) extends NativeThread{ /** - * @phpstan-param \ThreadedArray $channel + * @phpstan-param ThreadSafeArray $channel */ public function __construct( - private \ThreadedArray $channel, + private ThreadSafeArray $channel, ){} public function run() : void{ @@ -73,7 +74,7 @@ $thread = new class($channel) extends \Thread{ } }; -$thread->start(PTHREADS_INHERIT_NONE); +$thread->start(NativeThread::INHERIT_NONE); while(!feof($socket)){ $line = $channel->synchronized(function() use ($channel) : ?string{ if(count($channel) === 0){ diff --git a/src/network/mcpe/raklib/PthreadsChannelReader.php b/src/network/mcpe/raklib/PthreadsChannelReader.php index 68c718b0f..44057c27c 100644 --- a/src/network/mcpe/raklib/PthreadsChannelReader.php +++ b/src/network/mcpe/raklib/PthreadsChannelReader.php @@ -23,13 +23,14 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\raklib; +use pmmp\thread\ThreadSafeArray; use raklib\server\ipc\InterThreadChannelReader; final class PthreadsChannelReader implements InterThreadChannelReader{ /** - * @phpstan-param \ThreadedArray $buffer + * @phpstan-param ThreadSafeArray $buffer */ - public function __construct(private \ThreadedArray $buffer){} + public function __construct(private ThreadSafeArray $buffer){} public function read() : ?string{ return $this->buffer->shift(); diff --git a/src/network/mcpe/raklib/PthreadsChannelWriter.php b/src/network/mcpe/raklib/PthreadsChannelWriter.php index afbeefdd2..a85415d8d 100644 --- a/src/network/mcpe/raklib/PthreadsChannelWriter.php +++ b/src/network/mcpe/raklib/PthreadsChannelWriter.php @@ -23,13 +23,14 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\raklib; +use pmmp\thread\ThreadSafeArray; use raklib\server\ipc\InterThreadChannelWriter; final class PthreadsChannelWriter implements InterThreadChannelWriter{ /** - * @phpstan-param \ThreadedArray $buffer + * @phpstan-param ThreadSafeArray $buffer */ - public function __construct(private \ThreadedArray $buffer){} + public function __construct(private ThreadSafeArray $buffer){} public function write(string $str) : void{ $this->buffer[] = $str; diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 6a9f0f0b0..68f02b649 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\raklib; +use pmmp\thread\ThreadSafeArray; use pocketmine\lang\KnownTranslationFactory; use pocketmine\network\AdvancedNetworkInterface; use pocketmine\network\mcpe\compression\ZlibCompressor; @@ -105,10 +106,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ $this->sleeper = new SleeperNotifier(); - /** @phpstan-var \ThreadedArray $mainToThreadBuffer */ - $mainToThreadBuffer = new \ThreadedArray(); - /** @phpstan-var \ThreadedArray $threadToMainBuffer */ - $threadToMainBuffer = new \ThreadedArray(); + /** @phpstan-var ThreadSafeArray $mainToThreadBuffer */ + $mainToThreadBuffer = new ThreadSafeArray(); + /** @phpstan-var ThreadSafeArray $threadToMainBuffer */ + $threadToMainBuffer = new ThreadSafeArray(); $this->rakLib = new RakLibServer( $this->server->getLogger(), diff --git a/src/network/mcpe/raklib/RakLibServer.php b/src/network/mcpe/raklib/RakLibServer.php index 3238d1b44..3a3cea673 100644 --- a/src/network/mcpe/raklib/RakLibServer.php +++ b/src/network/mcpe/raklib/RakLibServer.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\raklib; +use pmmp\thread\Thread as NativeThread; +use pmmp\thread\ThreadSafeArray; use pocketmine\snooze\SleeperNotifier; use pocketmine\thread\NonThreadSafeValue; use pocketmine\thread\Thread; @@ -38,7 +40,6 @@ use function error_get_last; use function gc_enable; use function ini_set; use function register_shutdown_function; -use const PTHREADS_INHERIT_NONE; class RakLibServer extends Thread{ protected bool $cleanShutdown = false; @@ -50,13 +51,13 @@ class RakLibServer extends Thread{ protected NonThreadSafeValue $address; /** - * @phpstan-param \ThreadedArray $mainToThreadBuffer - * @phpstan-param \ThreadedArray $threadToMainBuffer + * @phpstan-param ThreadSafeArray $mainToThreadBuffer + * @phpstan-param ThreadSafeArray $threadToMainBuffer */ public function __construct( - protected \ThreadedLogger $logger, - protected \ThreadedArray $mainToThreadBuffer, - protected \ThreadedArray $threadToMainBuffer, + protected \ThreadSafeLogger $logger, + protected ThreadSafeArray $mainToThreadBuffer, + protected ThreadSafeArray $threadToMainBuffer, InternetAddress $address, protected int $serverId, protected int $maxMtuSize, @@ -88,13 +89,13 @@ class RakLibServer extends Thread{ } private function setCrashInfo(RakLibThreadCrashInfo $info) : void{ - $this->synchronized(function(RakLibThreadCrashInfo $info) : void{ + $this->synchronized(function() use ($info) : void{ $this->crashInfo = new NonThreadSafeValue($info); $this->notify(); - }, $info); + }); } - public function startAndWait(int $options = PTHREADS_INHERIT_NONE) : void{ + public function startAndWait(int $options = NativeThread::INHERIT_NONE) : void{ $this->start($options); $this->synchronized(function() : void{ while(!$this->ready && $this->crashInfo === null){ diff --git a/src/network/mcpe/raklib/SnoozeAwarePthreadsChannelWriter.php b/src/network/mcpe/raklib/SnoozeAwarePthreadsChannelWriter.php index 723cb3730..28f7be2b5 100644 --- a/src/network/mcpe/raklib/SnoozeAwarePthreadsChannelWriter.php +++ b/src/network/mcpe/raklib/SnoozeAwarePthreadsChannelWriter.php @@ -23,15 +23,16 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\raklib; +use pmmp\thread\ThreadSafeArray; use pocketmine\snooze\SleeperNotifier; use raklib\server\ipc\InterThreadChannelWriter; final class SnoozeAwarePthreadsChannelWriter implements InterThreadChannelWriter{ /** - * @phpstan-param \ThreadedArray $buffer + * @phpstan-param ThreadSafeArray $buffer */ public function __construct( - private \ThreadedArray $buffer, + private ThreadSafeArray $buffer, private SleeperNotifier $notifier ){} diff --git a/src/scheduler/AsyncPool.php b/src/scheduler/AsyncPool.php index 71dee756a..e04e58fd1 100644 --- a/src/scheduler/AsyncPool.php +++ b/src/scheduler/AsyncPool.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use pmmp\thread\Thread as NativeThread; +use pmmp\thread\ThreadSafeArray; use pocketmine\snooze\SleeperHandler; use pocketmine\snooze\SleeperNotifier; use pocketmine\utils\Utils; @@ -33,14 +35,13 @@ use function count; use function spl_object_id; use function time; use const PHP_INT_MAX; -use const PTHREADS_INHERIT_INI; /** * Manages general-purpose worker threads used for processing asynchronous tasks, and the tasks submitted to those * workers. */ class AsyncPool{ - private const WORKER_START_OPTIONS = PTHREADS_INHERIT_INI; + private const WORKER_START_OPTIONS = NativeThread::INHERIT_INI | NativeThread::INHERIT_COMMENTS; /** * @var \SplQueue[]|AsyncTask[][] @@ -69,7 +70,7 @@ class AsyncPool{ protected int $size, private int $workerMemoryLimit, private \ClassLoader $classLoader, - private \ThreadedLogger $logger, + private \ThreadSafeLogger $logger, private SleeperHandler $eventLoop ){} @@ -158,7 +159,7 @@ class AsyncPool{ throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once"); } - $task->progressUpdates = new \ThreadedArray(); + $task->progressUpdates = new ThreadSafeArray(); $task->setSubmitted(); $this->getWorker($worker)->stack($task); diff --git a/src/scheduler/AsyncTask.php b/src/scheduler/AsyncTask.php index 2194f47db..c48097bbc 100644 --- a/src/scheduler/AsyncTask.php +++ b/src/scheduler/AsyncTask.php @@ -23,7 +23,11 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use pmmp\thread\Runnable; +use pmmp\thread\Thread as NativeThread; +use pmmp\thread\ThreadSafeArray; use pocketmine\thread\NonThreadSafeValue; +use function assert; use function igbinary_serialize; use function igbinary_unserialize; use function is_null; @@ -54,7 +58,7 @@ use function spl_object_id; * If you want to store non-thread-safe objects to access when the task completes, store them using * {@link AsyncTask::storeLocal}. */ -abstract class AsyncTask extends \ThreadedRunnable{ +abstract class AsyncTask extends Runnable{ /** * @var \ArrayObject|mixed[]|null object hash => mixed data * @phpstan-var \ArrayObject>|null @@ -63,11 +67,8 @@ abstract class AsyncTask extends \ThreadedRunnable{ */ private static ?\ArrayObject $threadLocalStorage = null; - /** @var AsyncWorker|null $worker */ - public $worker = null; - - /** @phpstan-var \ThreadedArray */ - public \ThreadedArray $progressUpdates; + /** @phpstan-var ThreadSafeArray */ + public ThreadSafeArray $progressUpdates; /** @phpstan-var NonThreadSafeValue|string|int|bool|float|null */ private NonThreadSafeValue|string|int|bool|null|float $result = null; @@ -85,12 +86,15 @@ abstract class AsyncTask extends \ThreadedRunnable{ $this->onRun(); }catch(\Throwable $e){ $this->crashed = true; - $this->worker->handleException($e); + + \GlobalLogger::get()->logException($e); } } $this->finished = true; - $this->worker->getNotifier()->wakeupSleeper(); + $worker = NativeThread::getCurrentThread(); + assert($worker instanceof AsyncWorker); + $worker->getNotifier()->wakeupSleeper(); } public function isCrashed() : bool{ diff --git a/src/scheduler/AsyncWorker.php b/src/scheduler/AsyncWorker.php index 0b7087571..f012b61d3 100644 --- a/src/scheduler/AsyncWorker.php +++ b/src/scheduler/AsyncWorker.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use pmmp\thread\Thread as NativeThread; use pocketmine\snooze\SleeperNotifier; use pocketmine\thread\Worker; use function gc_enable; @@ -33,7 +34,7 @@ class AsyncWorker extends Worker{ private static array $store = []; public function __construct( - private \ThreadedLogger $logger, + private \ThreadSafeLogger $logger, private int $id, private int $memoryLimit, private SleeperNotifier $notifier @@ -57,7 +58,7 @@ class AsyncWorker extends Worker{ } } - public function getLogger() : \ThreadedLogger{ + public function getLogger() : \ThreadSafeLogger{ return $this->logger; } @@ -78,7 +79,7 @@ class AsyncWorker extends Worker{ * want to use on this worker thread from multiple AsyncTasks. */ public function saveToThreadStore(string $identifier, mixed $value) : void{ - if(\Thread::getCurrentThread() !== $this){ + if(NativeThread::getCurrentThread() !== $this){ throw new \LogicException("Thread-local data can only be stored in the thread context"); } self::$store[$identifier] = $value; @@ -93,7 +94,7 @@ class AsyncWorker extends Worker{ * Objects stored in this storage may ONLY be retrieved while the task is running. */ public function getFromThreadStore(string $identifier) : mixed{ - if(\Thread::getCurrentThread() !== $this){ + if(NativeThread::getCurrentThread() !== $this){ throw new \LogicException("Thread-local data can only be fetched in the thread context"); } return self::$store[$identifier] ?? null; @@ -103,7 +104,7 @@ class AsyncWorker extends Worker{ * Removes previously-stored mixed data from the worker's thread-local object store. */ public function removeFromThreadStore(string $identifier) : void{ - if(\Thread::getCurrentThread() !== $this){ + if(NativeThread::getCurrentThread() !== $this){ throw new \LogicException("Thread-local data can only be removed in the thread context"); } unset(self::$store[$identifier]); diff --git a/src/scheduler/DumpWorkerMemoryTask.php b/src/scheduler/DumpWorkerMemoryTask.php index b1cf3840c..5ef787b5b 100644 --- a/src/scheduler/DumpWorkerMemoryTask.php +++ b/src/scheduler/DumpWorkerMemoryTask.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use pmmp\thread\Thread as NativeThread; use pocketmine\MemoryManager; use Symfony\Component\Filesystem\Path; +use function assert; /** * Task used to dump memory from AsyncWorkers @@ -37,12 +39,14 @@ class DumpWorkerMemoryTask extends AsyncTask{ ){} public function onRun() : void{ + $worker = NativeThread::getCurrentThread(); + assert($worker instanceof AsyncWorker); MemoryManager::dumpMemory( - $this->worker, - Path::join($this->outputFolder, "AsyncWorker#" . $this->worker->getAsyncWorkerId()), + $worker, + Path::join($this->outputFolder, "AsyncWorker#" . $worker->getAsyncWorkerId()), $this->maxNesting, $this->maxStringSize, - new \PrefixedLogger($this->worker->getLogger(), "Memory Dump") + new \PrefixedLogger($worker->getLogger(), "Memory Dump") ); } } diff --git a/src/thread/CommonThreadPartsTrait.php b/src/thread/CommonThreadPartsTrait.php index 777acd009..a2429b056 100644 --- a/src/thread/CommonThreadPartsTrait.php +++ b/src/thread/CommonThreadPartsTrait.php @@ -23,16 +23,17 @@ declare(strict_types=1); namespace pocketmine\thread; +use pmmp\thread\ThreadSafeArray; use pocketmine\errorhandler\ErrorToExceptionHandler; use pocketmine\Server; use function error_reporting; trait CommonThreadPartsTrait{ /** - * @var \ThreadedArray|\ClassLoader[]|null - * @phpstan-var \ThreadedArray|null + * @var ThreadSafeArray|\ClassLoader[]|null + * @phpstan-var ThreadSafeArray|null */ - private ?\ThreadedArray $classLoaders = null; + private ?ThreadSafeArray $classLoaders = null; protected ?string $composerAutoloaderPath = null; protected bool $isKilled = false; @@ -55,14 +56,15 @@ trait CommonThreadPartsTrait{ } if($this->classLoaders === null){ - $this->classLoaders = new \ThreadedArray(); + $loaders = $this->classLoaders = new ThreadSafeArray(); }else{ + $loaders = $this->classLoaders; foreach($this->classLoaders as $k => $autoloader){ unset($this->classLoaders[$k]); } } foreach($autoloaders as $autoloader){ - $this->classLoaders[] = $autoloader; + $loaders[] = $autoloader; } } diff --git a/src/thread/NonThreadSafeValue.php b/src/thread/NonThreadSafeValue.php index 9d443b065..d0c65f4a4 100644 --- a/src/thread/NonThreadSafeValue.php +++ b/src/thread/NonThreadSafeValue.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\thread; +use pmmp\thread\ThreadSafe; use function get_debug_type; use function igbinary_serialize; use function igbinary_unserialize; @@ -34,7 +35,7 @@ use function igbinary_unserialize; * * @phpstan-template TValue */ -final class NonThreadSafeValue extends \ThreadedBase{ +final class NonThreadSafeValue extends ThreadSafe{ private string $variable; /** diff --git a/src/thread/Thread.php b/src/thread/Thread.php index 1c73cb1e2..706f96429 100644 --- a/src/thread/Thread.php +++ b/src/thread/Thread.php @@ -23,8 +23,8 @@ declare(strict_types=1); namespace pocketmine\thread; +use pmmp\thread\Thread as NativeThread; use pocketmine\scheduler\AsyncTask; -use const PTHREADS_INHERIT_NONE; /** * Specialized Thread class aimed at PocketMine-MP-related usages. It handles setting up autoloading and error handling. @@ -35,10 +35,10 @@ use const PTHREADS_INHERIT_NONE; * CPU. * @see AsyncTask */ -abstract class Thread extends \Thread{ +abstract class Thread extends NativeThread{ use CommonThreadPartsTrait; - public function start(int $options = PTHREADS_INHERIT_NONE) : bool{ + public function start(int $options = NativeThread::INHERIT_NONE) : bool{ //this is intentionally not traitified ThreadManager::getInstance()->add($this); diff --git a/src/thread/ThreadManager.php b/src/thread/ThreadManager.php index a60d9bf9e..0ec7f1b13 100644 --- a/src/thread/ThreadManager.php +++ b/src/thread/ThreadManager.php @@ -23,9 +23,11 @@ declare(strict_types=1); namespace pocketmine\thread; +use pmmp\thread\ThreadSafe; +use pmmp\thread\ThreadSafeArray; use function spl_object_id; -class ThreadManager extends \ThreadedBase{ +class ThreadManager extends ThreadSafe{ private static ?self $instance = null; @@ -40,11 +42,11 @@ class ThreadManager extends \ThreadedBase{ return self::$instance; } - /** @phpstan-var \ThreadedArray */ - private \ThreadedArray $threads; + /** @phpstan-var ThreadSafeArray */ + private ThreadSafeArray $threads; private function __construct(){ - $this->threads = new \ThreadedArray(); + $this->threads = new ThreadSafeArray(); } public function add(Worker|Thread $thread) : void{ diff --git a/src/thread/Worker.php b/src/thread/Worker.php index 572da3c67..3bc5cda97 100644 --- a/src/thread/Worker.php +++ b/src/thread/Worker.php @@ -23,8 +23,9 @@ declare(strict_types=1); namespace pocketmine\thread; +use pmmp\thread\Thread as NativeThread; +use pmmp\thread\Worker as NativeWorker; use pocketmine\scheduler\AsyncTask; -use const PTHREADS_INHERIT_NONE; /** * Specialized Worker class for PocketMine-MP-related use cases. It handles setting up autoloading and error handling. @@ -36,10 +37,10 @@ use const PTHREADS_INHERIT_NONE; * If you want to run tasks on other CPU cores, check out AsyncTask first. * @see AsyncTask */ -abstract class Worker extends \Worker{ +abstract class Worker extends NativeWorker{ use CommonThreadPartsTrait; - public function start(int $options = PTHREADS_INHERIT_NONE) : bool{ + public function start(int $options = NativeThread::INHERIT_NONE) : bool{ //this is intentionally not traitified ThreadManager::getInstance()->add($this); diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index f79615586..8658ff47e 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -24,14 +24,14 @@ declare(strict_types=1); namespace pocketmine\utils; use LogLevel; +use pmmp\thread\Thread as NativeThread; use pocketmine\thread\Thread; use pocketmine\thread\Worker; use function implode; use function sprintf; use const PHP_EOL; -use const PTHREADS_INHERIT_NONE; -class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ +class MainLogger extends \AttachableThreadSafeLogger implements \BufferedLogger{ protected bool $logDebug; private string $format = TextFormat::AQUA . "[%s] " . TextFormat::RESET . "%s[%s/%s]: %s" . TextFormat::RESET; @@ -52,7 +52,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $this->timezone = $timezone->getName(); $this->logWriterThread = new MainLoggerThread($logFile); - $this->logWriterThread->start(PTHREADS_INHERIT_NONE); + $this->logWriterThread->start(NativeThread::INHERIT_NONE); } /** @@ -165,7 +165,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ } public function shutdownLogWriterThread() : void{ - if(\Thread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ + if(NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ $this->logWriterThread->shutdown(); }else{ throw new \LogicException("Only the creator thread can shutdown the logger thread"); @@ -175,7 +175,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ protected function send(string $message, string $level, string $prefix, string $color) : void{ $time = new \DateTime('now', new \DateTimeZone($this->timezone)); - $thread = \Thread::getCurrentThread(); + $thread = NativeThread::getCurrentThread(); if($thread === null){ $threadName = $this->mainThreadName . " thread"; }elseif($thread instanceof Thread || $thread instanceof Worker){ @@ -195,7 +195,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL); /** - * @var \ThreadedLoggerAttachment $attachment + * @var \ThreadSafeLoggerAttachment $attachment */ foreach($this->attachments as $attachment){ $attachment->log($level, $message); @@ -208,7 +208,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ } public function __destruct(){ - if(!$this->logWriterThread->isJoined() && \Thread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ + if(!$this->logWriterThread->isJoined() && NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ $this->shutdownLogWriterThread(); } } diff --git a/src/utils/MainLoggerThread.php b/src/utils/MainLoggerThread.php index c7287e349..548e23a4f 100644 --- a/src/utils/MainLoggerThread.php +++ b/src/utils/MainLoggerThread.php @@ -23,22 +23,24 @@ declare(strict_types=1); namespace pocketmine\utils; +use pmmp\thread\Thread; +use pmmp\thread\ThreadSafeArray; use function fclose; use function fopen; use function fwrite; use function is_resource; use function touch; -final class MainLoggerThread extends \Thread{ - /** @phpstan-var \ThreadedArray */ - private \ThreadedArray $buffer; +final class MainLoggerThread extends Thread{ + /** @phpstan-var ThreadSafeArray */ + private ThreadSafeArray $buffer; private bool $syncFlush = false; private bool $shutdown = false; public function __construct( private string $logFile ){ - $this->buffer = new \ThreadedArray(); + $this->buffer = new ThreadSafeArray(); touch($this->logFile); } diff --git a/tests/phpstan/stubs/pthreads.stub b/tests/phpstan/stubs/pmmpthread.stub similarity index 70% rename from tests/phpstan/stubs/pthreads.stub rename to tests/phpstan/stubs/pmmpthread.stub index a48fceea0..9fe0a850a 100644 --- a/tests/phpstan/stubs/pthreads.stub +++ b/tests/phpstan/stubs/pmmpthread.stub @@ -1,9 +1,11 @@ */ -abstract class ThreadedBase implements \IteratorAggregate{ +abstract class ThreadSafe implements \IteratorAggregate{ /** * @template TReturn @@ -17,9 +19,9 @@ abstract class ThreadedBase implements \IteratorAggregate{ /** * @template TKey of array-key * @template TValue - * @implements ArrayAccess + * @implements \ArrayAccess */ -final class ThreadedArray extends ThreadedBase implements Countable, ArrayAccess{ +final class ThreadSafeArray extends ThreadSafe implements \Countable, \ArrayAccess{ /** * @return TValue|null @@ -30,4 +32,4 @@ final class ThreadedArray extends ThreadedBase implements Countable, ArrayAccess * @return TValue|null */ public function shift() : mixed{} -} \ No newline at end of file +}