mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 07:54:19 +00:00
Require pthreads ^5.1
This version of pthreads has a substantially improved API, improved performance, improved memory usage, and much less magical and broken behaviour.
This commit is contained in:
parent
14b250c63f
commit
222415859a
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
pm-version-major: "5"
|
||||
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
@ -42,7 +42,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
@ -81,7 +81,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
@ -122,7 +122,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
@ -161,7 +161,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
@ -22,7 +22,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pthreads": "^4.0",
|
||||
"ext-pthreads": "^5.1",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
@ -40,17 +40,17 @@
|
||||
"pocketmine/bedrock-protocol": "~18.0.0+bedrock-1.19.50",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
"pocketmine/classloader": "dev-pthreads-v5",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.18.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "dev-pthreads-v5",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
"pocketmine/nbt": "^0.3.2",
|
||||
"pocketmine/raklib": "^0.14.2",
|
||||
"pocketmine/raklib-ipc": "^0.1.0",
|
||||
"pocketmine/snooze": "^0.3.0",
|
||||
"pocketmine/snooze": "dev-pthreads-v5",
|
||||
"ramsey/uuid": "^4.1",
|
||||
"symfony/filesystem": "^5.4"
|
||||
},
|
||||
|
91
composer.lock
generated
91
composer.lock
generated
@ -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": "19f6b653d5b36e04f2d799de5972e567",
|
||||
"content-hash": "5725b919e65c02842812b1fed8a3d77c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -469,20 +469,20 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/classloader",
|
||||
"version": "0.2.0",
|
||||
"version": "dev-pthreads-v5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/ClassLoader.git",
|
||||
"reference": "49ea303993efdfb39cd302e2156d50aa78209e78"
|
||||
"reference": "dc98186e947d8940b8f6f4dbb2837f7c961a4812"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/49ea303993efdfb39cd302e2156d50aa78209e78",
|
||||
"reference": "49ea303993efdfb39cd302e2156d50aa78209e78",
|
||||
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/dc98186e947d8940b8f6f4dbb2837f7c961a4812",
|
||||
"reference": "dc98186e947d8940b8f6f4dbb2837f7c961a4812",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pthreads": "~3.2.0 || ^4.0",
|
||||
"ext-pthreads": "^5.0",
|
||||
"ext-reflection": "*",
|
||||
"php": "^8.0"
|
||||
},
|
||||
@ -491,8 +491,8 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "0.12.99",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.4",
|
||||
"phpstan/phpstan": "1.9.4",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
@ -508,9 +508,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.2.0"
|
||||
"source": "https://github.com/pmmp/ClassLoader/tree/pthreads-v5"
|
||||
},
|
||||
"time": "2021-11-01T20:17:27+00:00"
|
||||
"time": "2023-01-20T18:50:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/color",
|
||||
@ -591,16 +591,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.18.0",
|
||||
"version": "2.18.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "0f50afc3d0fec29f769a62e93c71f8a0fb968f76"
|
||||
"reference": "da25bfe9ee4822a84feb9b7e620c56ad4000aed0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/0f50afc3d0fec29f769a62e93c71f8a0fb968f76",
|
||||
"reference": "0f50afc3d0fec29f769a62e93c71f8a0fb968f76",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/da25bfe9ee4822a84feb9b7e620c56ad4000aed0",
|
||||
"reference": "da25bfe9ee4822a84feb9b7e620c56ad4000aed0",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -608,9 +608,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.18.0"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.18.3"
|
||||
},
|
||||
"time": "2023-01-14T17:52:46+00:00"
|
||||
"time": "2023-01-17T21:43:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
@ -655,21 +655,21 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log-pthreads",
|
||||
"version": "0.4.0",
|
||||
"version": "dev-pthreads-v5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/LogPthreads.git",
|
||||
"reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd"
|
||||
"reference": "83a66c9b8c39531b97a3b08c0ea97db967a3c60a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/61f709e8cf36bcc24e4efe02acded680a1ce23cd",
|
||||
"reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd",
|
||||
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/83a66c9b8c39531b97a3b08c0ea97db967a3c60a",
|
||||
"reference": "83a66c9b8c39531b97a3b08c0ea97db967a3c60a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pthreads": "~3.2.0 || ^4.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"ext-pthreads": "^5.0",
|
||||
"php": "^8.0",
|
||||
"pocketmine/log": "^0.4.0"
|
||||
},
|
||||
"conflict": {
|
||||
@ -677,8 +677,8 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "0.12.88",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.4"
|
||||
"phpstan/phpstan": "1.8.11",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -693,9 +693,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.4.0"
|
||||
"source": "https://github.com/pmmp/LogPthreads/tree/pthreads-v5"
|
||||
},
|
||||
"time": "2021-11-01T21:42:09+00:00"
|
||||
"time": "2023-01-20T19:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/math",
|
||||
@ -866,26 +866,26 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/snooze",
|
||||
"version": "0.3.1",
|
||||
"version": "dev-pthreads-v5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Snooze.git",
|
||||
"reference": "0ac8fc2a781c419a1f64ebca4d5835028f59e29b"
|
||||
"reference": "8589ddfa1672215dcc78d8edb7acb4cf67d59d5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/0ac8fc2a781c419a1f64ebca4d5835028f59e29b",
|
||||
"reference": "0ac8fc2a781c419a1f64ebca4d5835028f59e29b",
|
||||
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/8589ddfa1672215dcc78d8edb7acb4cf67d59d5a",
|
||||
"reference": "8589ddfa1672215dcc78d8edb7acb4cf67d59d5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pthreads": "~3.2.0 || ^4.0",
|
||||
"php-64bit": "^7.3 || ^8.0"
|
||||
"ext-pthreads": "^5.0",
|
||||
"php-64bit": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "0.12.99",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.4"
|
||||
"phpstan/phpstan": "1.9.14",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -900,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.3.1"
|
||||
"source": "https://github.com/pmmp/Snooze/tree/pthreads-v5"
|
||||
},
|
||||
"time": "2021-11-01T20:50:08+00:00"
|
||||
"time": "2023-01-20T18:19:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
@ -1610,16 +1610,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.15.2",
|
||||
"version": "v4.15.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
|
||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1660,9 +1660,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
|
||||
},
|
||||
"time": "2022-11-12T15:38:23+00:00"
|
||||
"time": "2023-01-16T22:05:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -3374,7 +3374,10 @@
|
||||
"stability-flags": {
|
||||
"pocketmine/bedrock-block-upgrade-schema": 20,
|
||||
"pocketmine/bedrock-data": 20,
|
||||
"pocketmine/bedrock-item-upgrade-schema": 20
|
||||
"pocketmine/bedrock-item-upgrade-schema": 20,
|
||||
"pocketmine/classloader": 20,
|
||||
"pocketmine/log-pthreads": 20,
|
||||
"pocketmine/snooze": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
@ -3396,7 +3399,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pthreads": "^4.0",
|
||||
"ext-pthreads": "^5.1",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
|
@ -122,8 +122,8 @@ namespace pocketmine {
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") >= 0){
|
||||
$messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version.";
|
||||
if(version_compare($pthreads_version, "5.1.0") < 0 || version_compare($pthreads_version, "6.0.0") >= 0){
|
||||
$messages[] = "pthreads ^5.0.0 is required, while you have $pthreads_version.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,17 @@ if($socket === false){
|
||||
throw new \RuntimeException("Failed to connect to server process ($errCode): $errMessage");
|
||||
}
|
||||
|
||||
$channel = new \Threaded();
|
||||
/** @phpstan-var \ThreadedArray<int, string> $channel */
|
||||
$channel = new \ThreadedArray();
|
||||
$thread = new class($channel) extends \Thread{
|
||||
/**
|
||||
* @phpstan-param \ThreadedArray<int, string> $channel
|
||||
*/
|
||||
public function __construct(
|
||||
private \Threaded $channel,
|
||||
private \ThreadedArray $channel,
|
||||
){}
|
||||
|
||||
public function run(){
|
||||
public function run() : void{
|
||||
require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
|
||||
$channel = $this->channel;
|
||||
@ -75,7 +79,6 @@ while(!feof($socket)){
|
||||
if(count($channel) === 0){
|
||||
$channel->wait(1_000_000);
|
||||
}
|
||||
/** @var string|null $line */
|
||||
$line = $channel->shift();
|
||||
return $line;
|
||||
});
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\ChunkPosition;
|
||||
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\FastChunkSerializer;
|
||||
|
||||
@ -43,14 +44,15 @@ class ChunkRequestTask extends AsyncTask{
|
||||
protected string $chunk;
|
||||
protected int $chunkX;
|
||||
protected int $chunkZ;
|
||||
protected Compressor $compressor;
|
||||
/** @phpstan-var NonThreadSafeValue<Compressor> */
|
||||
protected NonThreadSafeValue $compressor;
|
||||
private string $tiles;
|
||||
|
||||
/**
|
||||
* @phpstan-param (\Closure() : void)|null $onError
|
||||
*/
|
||||
public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor, ?\Closure $onError = null){
|
||||
$this->compressor = $compressor;
|
||||
$this->compressor = new NonThreadSafeValue($compressor);
|
||||
|
||||
$this->chunk = FastChunkSerializer::serializeTerrain($chunk);
|
||||
$this->chunkX = $chunkX;
|
||||
@ -66,7 +68,7 @@ class ChunkRequestTask extends AsyncTask{
|
||||
$subCount = ChunkSerializer::getSubChunkCount($chunk);
|
||||
$encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
|
||||
$payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles);
|
||||
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload))->getBuffer()));
|
||||
$this->setResult($this->compressor->deserialize()->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload))->getBuffer()));
|
||||
}
|
||||
|
||||
public function onError() : void{
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\network\mcpe\JwtUtils;
|
||||
use pocketmine\network\mcpe\protocol\types\login\JwtChainLinkBody;
|
||||
use pocketmine\network\mcpe\protocol\types\login\JwtHeader;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
use function base64_decode;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
@ -49,8 +50,10 @@ class ProcessLoginTask extends AsyncTask{
|
||||
* Whether the keychain signatures were validated correctly. This will be set to an error message if any link in the
|
||||
* keychain is invalid for whatever reason (bad signature, not in nbf-exp window, etc). If this is non-null, the
|
||||
* keychain might have been tampered with. The player will always be disconnected if this is non-null.
|
||||
*
|
||||
* @phpstan-var NonThreadSafeValue<Translatable>|string|null
|
||||
*/
|
||||
private Translatable|string|null $error = "Unknown";
|
||||
private NonThreadSafeValue|string|null $error = "Unknown";
|
||||
/**
|
||||
* Whether the player is logged into Xbox Live. This is true if any link in the keychain is signed with the Mojang
|
||||
* root public key.
|
||||
@ -77,7 +80,8 @@ class ProcessLoginTask extends AsyncTask{
|
||||
$this->clientPublicKey = $this->validateChain();
|
||||
$this->error = null;
|
||||
}catch(VerifyLoginException $e){
|
||||
$this->error = $e->getDisconnectMessage();
|
||||
$disconnectMessage = $e->getDisconnectMessage();
|
||||
$this->error = $disconnectMessage instanceof Translatable ? new NonThreadSafeValue($disconnectMessage) : $disconnectMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,6 +199,6 @@ class ProcessLoginTask extends AsyncTask{
|
||||
* @phpstan-var \Closure(bool, bool, Translatable|string|null, ?string) : void $callback
|
||||
*/
|
||||
$callback = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
|
||||
$callback($this->authenticated, $this->authRequired, $this->error, $this->clientPublicKey);
|
||||
$callback($this->authenticated, $this->authRequired, $this->error instanceof NonThreadSafeValue ? $this->error->deserialize() : $this->error, $this->clientPublicKey);
|
||||
}
|
||||
}
|
||||
|
@ -24,21 +24,26 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\compression;
|
||||
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
|
||||
class CompressBatchTask extends AsyncTask{
|
||||
|
||||
private const TLS_KEY_PROMISE = "promise";
|
||||
|
||||
/** @phpstan-var NonThreadSafeValue<Compressor> */
|
||||
private NonThreadSafeValue $compressor;
|
||||
|
||||
public function __construct(
|
||||
private string $data,
|
||||
CompressBatchPromise $promise,
|
||||
private Compressor $compressor
|
||||
Compressor $compressor
|
||||
){
|
||||
$this->compressor = new NonThreadSafeValue($compressor);
|
||||
$this->storeLocal(self::TLS_KEY_PROMISE, $promise);
|
||||
}
|
||||
|
||||
public function onRun() : void{
|
||||
$this->setResult($this->compressor->compress($this->data));
|
||||
$this->setResult($this->compressor->deserialize()->compress($this->data));
|
||||
}
|
||||
|
||||
public function onCompletion() : void{
|
||||
|
@ -26,7 +26,10 @@ namespace pocketmine\network\mcpe\raklib;
|
||||
use raklib\server\ipc\InterThreadChannelReader;
|
||||
|
||||
final class PthreadsChannelReader implements InterThreadChannelReader{
|
||||
public function __construct(private \Threaded $buffer){}
|
||||
/**
|
||||
* @phpstan-param \ThreadedArray<int, string> $buffer
|
||||
*/
|
||||
public function __construct(private \ThreadedArray $buffer){}
|
||||
|
||||
public function read() : ?string{
|
||||
return $this->buffer->shift();
|
||||
|
@ -26,7 +26,10 @@ namespace pocketmine\network\mcpe\raklib;
|
||||
use raklib\server\ipc\InterThreadChannelWriter;
|
||||
|
||||
final class PthreadsChannelWriter implements InterThreadChannelWriter{
|
||||
public function __construct(private \Threaded $buffer){}
|
||||
/**
|
||||
* @phpstan-param \ThreadedArray<int, string> $buffer
|
||||
*/
|
||||
public function __construct(private \ThreadedArray $buffer){}
|
||||
|
||||
public function write(string $str) : void{
|
||||
$this->buffer[] = $str;
|
||||
|
@ -85,8 +85,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
|
||||
$this->sleeper = new SleeperNotifier();
|
||||
|
||||
$mainToThreadBuffer = new \Threaded();
|
||||
$threadToMainBuffer = new \Threaded();
|
||||
/** @phpstan-var \ThreadedArray<int, string> $mainToThreadBuffer */
|
||||
$mainToThreadBuffer = new \ThreadedArray();
|
||||
/** @phpstan-var \ThreadedArray<int, string> $threadToMainBuffer */
|
||||
$threadToMainBuffer = new \ThreadedArray();
|
||||
|
||||
$this->rakLib = new RakLibServer(
|
||||
$this->server->getLogger(),
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\raklib;
|
||||
|
||||
use pocketmine\snooze\SleeperNotifier;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
use pocketmine\thread\Thread;
|
||||
use raklib\generic\Socket;
|
||||
use raklib\generic\SocketException;
|
||||
@ -43,19 +44,27 @@ class RakLibServer extends Thread{
|
||||
protected bool $cleanShutdown = false;
|
||||
protected bool $ready = false;
|
||||
protected string $mainPath;
|
||||
public ?RakLibThreadCrashInfo $crashInfo = null;
|
||||
/** @phpstan-var NonThreadSafeValue<RakLibThreadCrashInfo>|null */
|
||||
public ?NonThreadSafeValue $crashInfo = null;
|
||||
/** @phpstan-var NonThreadSafeValue<InternetAddress> */
|
||||
protected NonThreadSafeValue $address;
|
||||
|
||||
/**
|
||||
* @phpstan-param \ThreadedArray<int, string> $mainToThreadBuffer
|
||||
* @phpstan-param \ThreadedArray<int, string> $threadToMainBuffer
|
||||
*/
|
||||
public function __construct(
|
||||
protected \ThreadedLogger $logger,
|
||||
protected \Threaded $mainToThreadBuffer,
|
||||
protected \Threaded $threadToMainBuffer,
|
||||
protected InternetAddress $address,
|
||||
protected \ThreadedArray $mainToThreadBuffer,
|
||||
protected \ThreadedArray $threadToMainBuffer,
|
||||
InternetAddress $address,
|
||||
protected int $serverId,
|
||||
protected int $maxMtuSize,
|
||||
protected int $protocolVersion,
|
||||
protected SleeperNotifier $mainThreadNotifier
|
||||
){
|
||||
$this->mainPath = \pocketmine\PATH;
|
||||
$this->address = new NonThreadSafeValue($address);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,12 +84,12 @@ class RakLibServer extends Thread{
|
||||
}
|
||||
|
||||
public function getCrashInfo() : ?RakLibThreadCrashInfo{
|
||||
return $this->crashInfo;
|
||||
return $this->crashInfo?->deserialize();
|
||||
}
|
||||
|
||||
private function setCrashInfo(RakLibThreadCrashInfo $info) : void{
|
||||
$this->synchronized(function(RakLibThreadCrashInfo $info) : void{
|
||||
$this->crashInfo = $info;
|
||||
$this->crashInfo = new NonThreadSafeValue($info);
|
||||
$this->notify();
|
||||
}, $info);
|
||||
}
|
||||
@ -91,7 +100,7 @@ class RakLibServer extends Thread{
|
||||
while(!$this->ready && $this->crashInfo === null){
|
||||
$this->wait();
|
||||
}
|
||||
$crashInfo = $this->crashInfo;
|
||||
$crashInfo = $this->crashInfo?->deserialize();
|
||||
if($crashInfo !== null){
|
||||
if($crashInfo->getClass() === SocketException::class){
|
||||
throw new SocketException($crashInfo->getMessage());
|
||||
@ -110,7 +119,7 @@ class RakLibServer extends Thread{
|
||||
register_shutdown_function([$this, "shutdownHandler"]);
|
||||
|
||||
try{
|
||||
$socket = new Socket($this->address);
|
||||
$socket = new Socket($this->address->deserialize());
|
||||
}catch(SocketException $e){
|
||||
$this->setCrashInfo(RakLibThreadCrashInfo::fromThrowable($e));
|
||||
return;
|
||||
|
@ -27,8 +27,11 @@ use pocketmine\snooze\SleeperNotifier;
|
||||
use raklib\server\ipc\InterThreadChannelWriter;
|
||||
|
||||
final class SnoozeAwarePthreadsChannelWriter implements InterThreadChannelWriter{
|
||||
/**
|
||||
* @phpstan-param \ThreadedArray<int, string> $buffer
|
||||
*/
|
||||
public function __construct(
|
||||
private \Threaded $buffer,
|
||||
private \ThreadedArray $buffer,
|
||||
private SleeperNotifier $notifier
|
||||
){}
|
||||
|
||||
|
@ -158,7 +158,7 @@ class AsyncPool{
|
||||
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
|
||||
}
|
||||
|
||||
$task->progressUpdates = new \Threaded();
|
||||
$task->progressUpdates = new \ThreadedArray();
|
||||
$task->setSubmitted();
|
||||
|
||||
$this->getWorker($worker)->stack($task);
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\scheduler;
|
||||
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
use function is_null;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
@ -51,15 +51,10 @@ use function spl_object_id;
|
||||
* thread, e.g. during {@link AsyncTask::onCompletion()} or {@link AsyncTask::onProgressUpdate()}. This means that
|
||||
* whatever you do in onRun() must be able to work without the Server instance.
|
||||
*
|
||||
* WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
|
||||
* If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
|
||||
* If you want to store non-serializable objects to access when the task completes, store them using
|
||||
* If you want to store non-thread-safe objects to access when the task completes, store them using
|
||||
* {@link AsyncTask::storeLocal}.
|
||||
*
|
||||
* WARNING: Arrays are converted to Volatile objects when assigned as members of Threaded objects.
|
||||
* Keep this in mind when using arrays stored as members of your AsyncTask.
|
||||
*/
|
||||
abstract class AsyncTask extends \Threaded{
|
||||
abstract class AsyncTask extends \ThreadedRunnable{
|
||||
/**
|
||||
* @var \ArrayObject|mixed[]|null object hash => mixed data
|
||||
* @phpstan-var \ArrayObject<int, array<string, mixed>>|null
|
||||
@ -71,10 +66,11 @@ abstract class AsyncTask extends \Threaded{
|
||||
/** @var AsyncWorker|null $worker */
|
||||
public $worker = null;
|
||||
|
||||
public \Threaded $progressUpdates;
|
||||
/** @phpstan-var \ThreadedArray<int, string> */
|
||||
public \ThreadedArray $progressUpdates;
|
||||
|
||||
private string|int|bool|null|float $result = null;
|
||||
private bool $serialized = false;
|
||||
/** @phpstan-var NonThreadSafeValue<mixed>|string|int|bool|float|null */
|
||||
private NonThreadSafeValue|string|int|bool|null|float $result = null;
|
||||
private bool $cancelRun = false;
|
||||
private bool $submitted = false;
|
||||
|
||||
@ -117,15 +113,14 @@ abstract class AsyncTask extends \Threaded{
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResult(){
|
||||
if($this->serialized){
|
||||
if(!is_string($this->result)) throw new AssumptionFailedError("Result expected to be a serialized string");
|
||||
return igbinary_unserialize($this->result);
|
||||
if($this->result instanceof NonThreadSafeValue){
|
||||
return $this->result->deserialize();
|
||||
}
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function setResult(mixed $result) : void{
|
||||
$this->result = ($this->serialized = !is_scalar($result)) ? igbinary_serialize($result) : $result;
|
||||
$this->result = is_scalar($result) || is_null($result) ? $result : new NonThreadSafeValue($result);
|
||||
}
|
||||
|
||||
public function cancelRun() : void{
|
||||
@ -164,15 +159,14 @@ abstract class AsyncTask extends \Threaded{
|
||||
* @param mixed $progress A value that can be safely serialize()'ed.
|
||||
*/
|
||||
public function publishProgress(mixed $progress) : void{
|
||||
$this->progressUpdates[] = igbinary_serialize($progress);
|
||||
$this->progressUpdates[] = igbinary_serialize($progress) ?? throw new \InvalidArgumentException("Progress must be serializable");
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Only call from AsyncPool.php on the main thread
|
||||
*/
|
||||
public function checkProgressUpdates() : void{
|
||||
while($this->progressUpdates->count() !== 0){
|
||||
$progress = $this->progressUpdates->shift();
|
||||
while(($progress = $this->progressUpdates->shift()) !== null){
|
||||
$this->onProgressUpdate(igbinary_unserialize($progress));
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,11 @@ use pocketmine\Server;
|
||||
use function error_reporting;
|
||||
|
||||
trait CommonThreadPartsTrait{
|
||||
/** @var \Threaded|\ClassLoader[]|null */
|
||||
private ?\Threaded $classLoaders = null;
|
||||
/**
|
||||
* @var \ThreadedArray|\ClassLoader[]|null
|
||||
* @phpstan-var \ThreadedArray<int, \ClassLoader>|null
|
||||
*/
|
||||
private ?\ThreadedArray $classLoaders = null;
|
||||
protected ?string $composerAutoloaderPath = null;
|
||||
|
||||
protected bool $isKilled = false;
|
||||
@ -52,7 +55,7 @@ trait CommonThreadPartsTrait{
|
||||
}
|
||||
|
||||
if($this->classLoaders === null){
|
||||
$this->classLoaders = new \Threaded();
|
||||
$this->classLoaders = new \ThreadedArray();
|
||||
}else{
|
||||
foreach($this->classLoaders as $k => $autoloader){
|
||||
unset($this->classLoaders[$k]);
|
||||
|
57
src/thread/NonThreadSafeValue.php
Normal file
57
src/thread/NonThreadSafeValue.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\thread;
|
||||
|
||||
use function get_debug_type;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
|
||||
/**
|
||||
* This class automatically serializes values which can't be shared between threads.
|
||||
* This class does NOT enable sharing the variable between threads. Each call to deserialize() will return a new copy
|
||||
* of the variable.
|
||||
*
|
||||
* @phpstan-template TValue
|
||||
*/
|
||||
final class NonThreadSafeValue extends \ThreadedBase{
|
||||
private string $variable;
|
||||
|
||||
/**
|
||||
* @phpstan-param TValue $variable
|
||||
*/
|
||||
public function __construct(
|
||||
mixed $variable
|
||||
){
|
||||
$this->variable = igbinary_serialize($variable) ?? throw new \InvalidArgumentException("Cannot serialize variable of type " . get_debug_type($variable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deserialized copy of the original variable.
|
||||
*
|
||||
* @phpstan-return TValue
|
||||
*/
|
||||
public function deserialize() : mixed{
|
||||
return igbinary_unserialize($this->variable);
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ namespace pocketmine\thread;
|
||||
|
||||
use function spl_object_id;
|
||||
|
||||
class ThreadManager extends \Volatile{
|
||||
class ThreadManager extends \ThreadedBase{
|
||||
|
||||
private static ?self $instance = null;
|
||||
|
||||
@ -40,12 +40,19 @@ class ThreadManager extends \Volatile{
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/** @phpstan-var \ThreadedArray<int, Thread|Worker> */
|
||||
private \ThreadedArray $threads;
|
||||
|
||||
private function __construct(){
|
||||
$this->threads = new \ThreadedArray();
|
||||
}
|
||||
|
||||
public function add(Worker|Thread $thread) : void{
|
||||
$this[spl_object_id($thread)] = $thread;
|
||||
$this->threads[spl_object_id($thread)] = $thread;
|
||||
}
|
||||
|
||||
public function remove(Worker|Thread $thread) : void{
|
||||
unset($this[spl_object_id($thread)]);
|
||||
unset($this->threads[spl_object_id($thread)]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +63,7 @@ class ThreadManager extends \Volatile{
|
||||
/**
|
||||
* @var Worker|Thread $thread
|
||||
*/
|
||||
foreach($this as $key => $thread){
|
||||
foreach($this->threads as $key => $thread){
|
||||
$array[$key] = $thread;
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,9 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{
|
||||
Terminal::writeLine($message);
|
||||
$this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL);
|
||||
|
||||
/**
|
||||
* @var \ThreadedLoggerAttachment $attachment
|
||||
*/
|
||||
foreach($this->attachments as $attachment){
|
||||
$attachment->log($level, $message);
|
||||
}
|
||||
|
@ -30,14 +30,15 @@ use function is_resource;
|
||||
use function touch;
|
||||
|
||||
final class MainLoggerThread extends \Thread{
|
||||
private \Threaded $buffer;
|
||||
/** @phpstan-var \ThreadedArray<int, string> */
|
||||
private \ThreadedArray $buffer;
|
||||
private bool $syncFlush = false;
|
||||
private bool $shutdown = false;
|
||||
|
||||
public function __construct(
|
||||
private string $logFile
|
||||
){
|
||||
$this->buffer = new \Threaded();
|
||||
$this->buffer = new \ThreadedArray();
|
||||
touch($this->logFile);
|
||||
}
|
||||
|
||||
@ -72,9 +73,7 @@ final class MainLoggerThread extends \Thread{
|
||||
* @param resource $logResource
|
||||
*/
|
||||
private function writeLogStream($logResource) : void{
|
||||
while($this->buffer->count() > 0){
|
||||
/** @var string $chunk */
|
||||
$chunk = $this->buffer->shift();
|
||||
while(($chunk = $this->buffer->shift()) !== null){
|
||||
fwrite($logResource, $chunk);
|
||||
}
|
||||
|
||||
|
@ -46,9 +46,9 @@ parameters:
|
||||
path: ../../../src/plugin/PluginManager.php
|
||||
|
||||
-
|
||||
message: "#^Offset \\(int\\|string\\) on array\\<pocketmine\\\\plugin\\\\Plugin\\> in isset\\(\\) always exists and is not nullable\\.$#"
|
||||
message: "#^Parameter \\#1 \\$work of method Worker\\:\\:stack\\(\\) expects Threaded, pocketmine\\\\scheduler\\\\AsyncTask given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/plugin/PluginManager.php
|
||||
path: ../../../src/scheduler/AsyncPool.php
|
||||
|
||||
-
|
||||
message: "#^Static property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$threadLocalStorage \\(ArrayObject\\<int, array\\<string, mixed\\>\\>\\|null\\) does not accept non\\-empty\\-array\\<int, non\\-empty\\-array\\<string, mixed\\>\\>\\|ArrayObject\\<int, array\\<string, mixed\\>\\>\\.$#"
|
||||
@ -56,12 +56,12 @@ parameters:
|
||||
path: ../../../src/scheduler/AsyncTask.php
|
||||
|
||||
-
|
||||
message: "#^Property pocketmine\\\\thread\\\\Thread\\:\\:\\$classLoaders \\(\\(iterable\\<ClassLoader\\>&Threaded\\)\\|null\\) does not accept array\\<int, ClassLoader\\>\\|\\(iterable\\<ClassLoader\\>&Threaded\\)\\.$#"
|
||||
message: "#^Property pocketmine\\\\thread\\\\Thread\\:\\:\\$classLoaders \\(ThreadedArray\\<int, ClassLoader\\>\\|null\\) does not accept array\\{ClassLoader\\}\\|ThreadedArray\\<int, ClassLoader\\>\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/thread/Thread.php
|
||||
|
||||
-
|
||||
message: "#^Property pocketmine\\\\thread\\\\Worker\\:\\:\\$classLoaders \\(\\(iterable\\<ClassLoader\\>&Threaded\\)\\|null\\) does not accept array\\<int, ClassLoader\\>\\|\\(iterable\\<ClassLoader\\>&Threaded\\)\\.$#"
|
||||
message: "#^Property pocketmine\\\\thread\\\\Worker\\:\\:\\$classLoaders \\(ThreadedArray\\<int, ClassLoader\\>\\|null\\) does not accept array\\{ClassLoader\\}\\|ThreadedArray\\<int, ClassLoader\\>\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/thread/Worker.php
|
||||
|
||||
|
@ -1,6 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @implements \Traversable<array-key, mixed>
|
||||
* @implements \IteratorAggregate<array-key, mixed>
|
||||
*/
|
||||
class Threaded implements \Traversable{}
|
||||
abstract class ThreadedBase implements \IteratorAggregate{
|
||||
|
||||
/**
|
||||
* @template TReturn
|
||||
* @param \Closure() : TReturn $function
|
||||
* @param mixed ...$args
|
||||
* @return TReturn
|
||||
*/
|
||||
public function synchronized(\Closure $function, mixed ...$args) : mixed{}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @implements ArrayAccess<TKey, TValue>
|
||||
*/
|
||||
final class ThreadedArray extends ThreadedBase implements Countable, ArrayAccess{
|
||||
|
||||
/**
|
||||
* @return TValue|null
|
||||
*/
|
||||
public function pop() : mixed{}
|
||||
|
||||
/**
|
||||
* @return TValue|null
|
||||
*/
|
||||
public function shift() : mixed{}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user