pmmpthread support

This commit is contained in:
Dylan K. Taylor 2023-05-20 01:29:26 +01:00
parent 8454076235
commit e0630fbb25
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
24 changed files with 159 additions and 126 deletions

View File

@ -17,7 +17,7 @@ jobs:
steps: steps:
- name: Build and prepare PHP cache - name: Build and prepare PHP cache
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
@ -38,7 +38,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
@ -77,7 +77,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
@ -118,7 +118,7 @@ jobs:
submodules: true submodules: true
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
@ -157,7 +157,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2 uses: pmmp/setup-php-action@fa2accea978a84097cf40ecc7d46b2d71f258bd5
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"

View File

@ -22,7 +22,7 @@
"ext-openssl": "*", "ext-openssl": "*",
"ext-pcre": "*", "ext-pcre": "*",
"ext-phar": "*", "ext-phar": "*",
"ext-pthreads": "^5.1", "ext-pmmpthread": "^6.0",
"ext-reflection": "*", "ext-reflection": "*",
"ext-simplexml": "*", "ext-simplexml": "*",
"ext-sockets": "*", "ext-sockets": "*",
@ -40,17 +40,17 @@
"pocketmine/bedrock-protocol": "~21.0.0+bedrock-1.19.80", "pocketmine/bedrock-protocol": "~21.0.0+bedrock-1.19.80",
"pocketmine/binaryutils": "^0.2.1", "pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2", "pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.3.0", "pocketmine/classloader": "dev-stable",
"pocketmine/color": "^0.3.0", "pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0", "pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.19.0", "pocketmine/locale-data": "~2.19.0",
"pocketmine/log": "^0.4.0", "pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.5.0", "pocketmine/log-pthreads": "dev-stable",
"pocketmine/math": "^0.4.0", "pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.2", "pocketmine/nbt": "^0.3.2",
"pocketmine/raklib": "^0.15.0", "pocketmine/raklib": "^0.15.0",
"pocketmine/raklib-ipc": "^0.2.0", "pocketmine/raklib-ipc": "^0.2.0",
"pocketmine/snooze": "^0.4.0", "pocketmine/snooze": "dev-master",
"ramsey/uuid": "^4.1", "ramsey/uuid": "^4.1",
"symfony/filesystem": "^5.4" "symfony/filesystem": "^5.4"
}, },

79
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "8c09886bd34e74a61c3ea1ee2be3b2e9", "content-hash": "507c2a45350440a7717ed089190fe4f0",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -466,32 +466,33 @@
}, },
{ {
"name": "pocketmine/classloader", "name": "pocketmine/classloader",
"version": "0.3.0", "version": "dev-stable",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/ClassLoader.git", "url": "https://github.com/pmmp/ClassLoader.git",
"reference": "407caf521186ec1f03024f39031cc681ad491026" "reference": "e15c9b4d310581d2d2c9bf2794869cb940e011e1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/407caf521186ec1f03024f39031cc681ad491026", "url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/e15c9b4d310581d2d2c9bf2794869cb940e011e1",
"reference": "407caf521186ec1f03024f39031cc681ad491026", "reference": "e15c9b4d310581d2d2c9bf2794869cb940e011e1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-pthreads": "^5.0", "ext-pmmpthread": "^6.0",
"ext-reflection": "*", "ext-reflection": "*",
"php": "^8.0" "php": "^8.1"
}, },
"conflict": { "conflict": {
"pocketmine/spl": "<0.4" "pocketmine/spl": "<0.4"
}, },
"require-dev": { "require-dev": {
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.9.4", "phpstan/phpstan": "1.10.15",
"phpstan/phpstan-strict-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5" "phpunit/phpunit": "^9.5"
}, },
"default-branch": true,
"type": "library", "type": "library",
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -505,9 +506,9 @@
"description": "Ad-hoc autoloading components used by PocketMine-MP", "description": "Ad-hoc autoloading components used by PocketMine-MP",
"support": { "support": {
"issues": "https://github.com/pmmp/ClassLoader/issues", "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", "name": "pocketmine/color",
@ -652,21 +653,21 @@
}, },
{ {
"name": "pocketmine/log-pthreads", "name": "pocketmine/log-pthreads",
"version": "0.5.0", "version": "dev-stable",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/LogPthreads.git", "url": "https://github.com/pmmp/LogPthreads.git",
"reference": "0ecfea6dcfc9a9f5c86e126ac1661732de5c5666" "reference": "bb3b5395042d12ec0d7ad5c855fd86eaf12869d3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/0ecfea6dcfc9a9f5c86e126ac1661732de5c5666", "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/bb3b5395042d12ec0d7ad5c855fd86eaf12869d3",
"reference": "0ecfea6dcfc9a9f5c86e126ac1661732de5c5666", "reference": "bb3b5395042d12ec0d7ad5c855fd86eaf12869d3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-pthreads": "^5.0", "ext-pmmpthread": "^6.0",
"php": "^8.0", "php": "^8.1",
"pocketmine/log": "^0.4.0" "pocketmine/log": "^0.4.0"
}, },
"conflict": { "conflict": {
@ -674,9 +675,10 @@
}, },
"require-dev": { "require-dev": {
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.8.11", "phpstan/phpstan": "1.10.3",
"phpstan/phpstan-strict-rules": "^1.0" "phpstan/phpstan-strict-rules": "^1.0"
}, },
"default-branch": true,
"type": "library", "type": "library",
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -690,9 +692,9 @@
"description": "Logging components specialized for pthreads used by PocketMine-MP and related projects", "description": "Logging components specialized for pthreads used by PocketMine-MP and related projects",
"support": { "support": {
"issues": "https://github.com/pmmp/LogPthreads/issues", "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", "name": "pocketmine/math",
@ -863,27 +865,28 @@
}, },
{ {
"name": "pocketmine/snooze", "name": "pocketmine/snooze",
"version": "0.4.0", "version": "dev-master",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/Snooze.git", "url": "https://github.com/pmmp/Snooze.git",
"reference": "6b1d6cc645d674590ff9be2438ac00032f9ee292" "reference": "3207a201cbb10eebb4a96749678f7adef216bb71"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/Snooze/zipball/6b1d6cc645d674590ff9be2438ac00032f9ee292", "url": "https://api.github.com/repos/pmmp/Snooze/zipball/3207a201cbb10eebb4a96749678f7adef216bb71",
"reference": "6b1d6cc645d674590ff9be2438ac00032f9ee292", "reference": "3207a201cbb10eebb4a96749678f7adef216bb71",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-pthreads": "^5.0", "ext-pmmpthread": "^6.0",
"php-64bit": "^8.0" "php-64bit": "^8.1"
}, },
"require-dev": { "require-dev": {
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.9.14", "phpstan/phpstan": "1.10.3",
"phpstan/phpstan-strict-rules": "^1.0" "phpstan/phpstan-strict-rules": "^1.0"
}, },
"default-branch": true,
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -897,9 +900,9 @@
"description": "Thread notification management library for code using the pthreads extension", "description": "Thread notification management library for code using the pthreads extension",
"support": { "support": {
"issues": "https://github.com/pmmp/Snooze/issues", "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", "name": "ramsey/collection",
@ -1527,16 +1530,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.15.4", "version": "v4.15.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1577,9 +1580,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "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", "name": "phar-io/manifest",
@ -3293,7 +3296,11 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {
"pocketmine/classloader": 20,
"pocketmine/log-pthreads": 20,
"pocketmine/snooze": 20
},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
@ -3314,7 +3321,7 @@
"ext-openssl": "*", "ext-openssl": "*",
"ext-pcre": "*", "ext-pcre": "*",
"ext-phar": "*", "ext-phar": "*",
"ext-pthreads": "^5.1", "ext-pmmpthread": "^6.0",
"ext-reflection": "*", "ext-reflection": "*",
"ext-simplexml": "*", "ext-simplexml": "*",
"ext-sockets": "*", "ext-sockets": "*",

View File

@ -44,7 +44,7 @@ parameters:
- tests/phpstan/stubs/JsonMapper.stub - tests/phpstan/stubs/JsonMapper.stub
- tests/phpstan/stubs/leveldb.stub - tests/phpstan/stubs/leveldb.stub
- tests/phpstan/stubs/phpasn1.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 reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
staticReflectionClassNamePatterns: staticReflectionClassNamePatterns:
- "#^COM$#" - "#^COM$#"

View File

@ -338,7 +338,7 @@ JIT_WARNING
$logger->info("Stopping other threads"); $logger->info("Stopping other threads");
$killer = new ServerKiller(8); $killer = new ServerKiller(8);
$killer->start(PTHREADS_INHERIT_NONE); $killer->start();
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
if(ThreadManager::getInstance()->stopAll() > 0){ if(ThreadManager::getInstance()->stopAll() > 0){

View File

@ -417,7 +417,7 @@ class Server{
return $this->autoloader; return $this->autoloader;
} }
public function getLogger() : \AttachableThreadedLogger{ public function getLogger() : \AttachableThreadSafeLogger{
return $this->logger; return $this->logger;
} }
@ -760,7 +760,7 @@ class Server{
public function __construct( public function __construct(
private \DynamicClassLoader $autoloader, private \DynamicClassLoader $autoloader,
private \AttachableThreadedLogger $logger, private \AttachableThreadSafeLogger $logger,
string $dataPath, string $dataPath,
string $pluginPath string $pluginPath
){ ){

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\console; namespace pocketmine\console;
use pmmp\thread\Thread as NativeThread;
use pmmp\thread\ThreadSafeArray;
use pocketmine\utils\Process; use pocketmine\utils\Process;
use function cli_set_process_title; use function cli_set_process_title;
use function count; use function count;
@ -30,7 +32,6 @@ use function dirname;
use function feof; use function feof;
use function fwrite; use function fwrite;
use function stream_socket_client; use function stream_socket_client;
use const PTHREADS_INHERIT_NONE;
require dirname(__DIR__, 2) . '/vendor/autoload.php'; 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"); throw new \RuntimeException("Failed to connect to server process ($errCode): $errMessage");
} }
/** @phpstan-var \ThreadedArray<int, string> $channel */ /** @phpstan-var ThreadSafeArray<int, string> $channel */
$channel = new \ThreadedArray(); $channel = new ThreadSafeArray();
$thread = new class($channel) extends \Thread{ $thread = new class($channel) extends NativeThread{
/** /**
* @phpstan-param \ThreadedArray<int, string> $channel * @phpstan-param ThreadSafeArray<int, string> $channel
*/ */
public function __construct( public function __construct(
private \ThreadedArray $channel, private ThreadSafeArray $channel,
){} ){}
public function run() : void{ 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)){ while(!feof($socket)){
$line = $channel->synchronized(function() use ($channel) : ?string{ $line = $channel->synchronized(function() use ($channel) : ?string{
if(count($channel) === 0){ if(count($channel) === 0){

View File

@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\raklib; namespace pocketmine\network\mcpe\raklib;
use pmmp\thread\ThreadSafeArray;
use raklib\server\ipc\InterThreadChannelReader; use raklib\server\ipc\InterThreadChannelReader;
final class PthreadsChannelReader implements InterThreadChannelReader{ final class PthreadsChannelReader implements InterThreadChannelReader{
/** /**
* @phpstan-param \ThreadedArray<int, string> $buffer * @phpstan-param ThreadSafeArray<int, string> $buffer
*/ */
public function __construct(private \ThreadedArray $buffer){} public function __construct(private ThreadSafeArray $buffer){}
public function read() : ?string{ public function read() : ?string{
return $this->buffer->shift(); return $this->buffer->shift();

View File

@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\raklib; namespace pocketmine\network\mcpe\raklib;
use pmmp\thread\ThreadSafeArray;
use raklib\server\ipc\InterThreadChannelWriter; use raklib\server\ipc\InterThreadChannelWriter;
final class PthreadsChannelWriter implements InterThreadChannelWriter{ final class PthreadsChannelWriter implements InterThreadChannelWriter{
/** /**
* @phpstan-param \ThreadedArray<int, string> $buffer * @phpstan-param ThreadSafeArray<int, string> $buffer
*/ */
public function __construct(private \ThreadedArray $buffer){} public function __construct(private ThreadSafeArray $buffer){}
public function write(string $str) : void{ public function write(string $str) : void{
$this->buffer[] = $str; $this->buffer[] = $str;

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\raklib; namespace pocketmine\network\mcpe\raklib;
use pmmp\thread\ThreadSafeArray;
use pocketmine\lang\KnownTranslationFactory; use pocketmine\lang\KnownTranslationFactory;
use pocketmine\network\AdvancedNetworkInterface; use pocketmine\network\AdvancedNetworkInterface;
use pocketmine\network\mcpe\compression\ZlibCompressor; use pocketmine\network\mcpe\compression\ZlibCompressor;
@ -105,10 +106,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$this->sleeper = new SleeperNotifier(); $this->sleeper = new SleeperNotifier();
/** @phpstan-var \ThreadedArray<int, string> $mainToThreadBuffer */ /** @phpstan-var ThreadSafeArray<int, string> $mainToThreadBuffer */
$mainToThreadBuffer = new \ThreadedArray(); $mainToThreadBuffer = new ThreadSafeArray();
/** @phpstan-var \ThreadedArray<int, string> $threadToMainBuffer */ /** @phpstan-var ThreadSafeArray<int, string> $threadToMainBuffer */
$threadToMainBuffer = new \ThreadedArray(); $threadToMainBuffer = new ThreadSafeArray();
$this->rakLib = new RakLibServer( $this->rakLib = new RakLibServer(
$this->server->getLogger(), $this->server->getLogger(),

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\raklib; namespace pocketmine\network\mcpe\raklib;
use pmmp\thread\Thread as NativeThread;
use pmmp\thread\ThreadSafeArray;
use pocketmine\snooze\SleeperNotifier; use pocketmine\snooze\SleeperNotifier;
use pocketmine\thread\NonThreadSafeValue; use pocketmine\thread\NonThreadSafeValue;
use pocketmine\thread\Thread; use pocketmine\thread\Thread;
@ -38,7 +40,6 @@ use function error_get_last;
use function gc_enable; use function gc_enable;
use function ini_set; use function ini_set;
use function register_shutdown_function; use function register_shutdown_function;
use const PTHREADS_INHERIT_NONE;
class RakLibServer extends Thread{ class RakLibServer extends Thread{
protected bool $cleanShutdown = false; protected bool $cleanShutdown = false;
@ -50,13 +51,13 @@ class RakLibServer extends Thread{
protected NonThreadSafeValue $address; protected NonThreadSafeValue $address;
/** /**
* @phpstan-param \ThreadedArray<int, string> $mainToThreadBuffer * @phpstan-param ThreadSafeArray<int, string> $mainToThreadBuffer
* @phpstan-param \ThreadedArray<int, string> $threadToMainBuffer * @phpstan-param ThreadSafeArray<int, string> $threadToMainBuffer
*/ */
public function __construct( public function __construct(
protected \ThreadedLogger $logger, protected \ThreadSafeLogger $logger,
protected \ThreadedArray $mainToThreadBuffer, protected ThreadSafeArray $mainToThreadBuffer,
protected \ThreadedArray $threadToMainBuffer, protected ThreadSafeArray $threadToMainBuffer,
InternetAddress $address, InternetAddress $address,
protected int $serverId, protected int $serverId,
protected int $maxMtuSize, protected int $maxMtuSize,
@ -88,13 +89,13 @@ class RakLibServer extends Thread{
} }
private function setCrashInfo(RakLibThreadCrashInfo $info) : void{ private function setCrashInfo(RakLibThreadCrashInfo $info) : void{
$this->synchronized(function(RakLibThreadCrashInfo $info) : void{ $this->synchronized(function() use ($info) : void{
$this->crashInfo = new NonThreadSafeValue($info); $this->crashInfo = new NonThreadSafeValue($info);
$this->notify(); $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->start($options);
$this->synchronized(function() : void{ $this->synchronized(function() : void{
while(!$this->ready && $this->crashInfo === null){ while(!$this->ready && $this->crashInfo === null){

View File

@ -23,15 +23,16 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\raklib; namespace pocketmine\network\mcpe\raklib;
use pmmp\thread\ThreadSafeArray;
use pocketmine\snooze\SleeperNotifier; use pocketmine\snooze\SleeperNotifier;
use raklib\server\ipc\InterThreadChannelWriter; use raklib\server\ipc\InterThreadChannelWriter;
final class SnoozeAwarePthreadsChannelWriter implements InterThreadChannelWriter{ final class SnoozeAwarePthreadsChannelWriter implements InterThreadChannelWriter{
/** /**
* @phpstan-param \ThreadedArray<int, string> $buffer * @phpstan-param ThreadSafeArray<int, string> $buffer
*/ */
public function __construct( public function __construct(
private \ThreadedArray $buffer, private ThreadSafeArray $buffer,
private SleeperNotifier $notifier private SleeperNotifier $notifier
){} ){}

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pmmp\thread\Thread as NativeThread;
use pmmp\thread\ThreadSafeArray;
use pocketmine\snooze\SleeperHandler; use pocketmine\snooze\SleeperHandler;
use pocketmine\snooze\SleeperNotifier; use pocketmine\snooze\SleeperNotifier;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
@ -33,14 +35,13 @@ use function count;
use function spl_object_id; use function spl_object_id;
use function time; use function time;
use const PHP_INT_MAX; 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 * Manages general-purpose worker threads used for processing asynchronous tasks, and the tasks submitted to those
* workers. * workers.
*/ */
class AsyncPool{ class AsyncPool{
private const WORKER_START_OPTIONS = PTHREADS_INHERIT_INI; private const WORKER_START_OPTIONS = NativeThread::INHERIT_INI | NativeThread::INHERIT_COMMENTS;
/** /**
* @var \SplQueue[]|AsyncTask[][] * @var \SplQueue[]|AsyncTask[][]
@ -69,7 +70,7 @@ class AsyncPool{
protected int $size, protected int $size,
private int $workerMemoryLimit, private int $workerMemoryLimit,
private \ClassLoader $classLoader, private \ClassLoader $classLoader,
private \ThreadedLogger $logger, private \ThreadSafeLogger $logger,
private SleeperHandler $eventLoop private SleeperHandler $eventLoop
){} ){}
@ -158,7 +159,7 @@ class AsyncPool{
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once"); throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
} }
$task->progressUpdates = new \ThreadedArray(); $task->progressUpdates = new ThreadSafeArray();
$task->setSubmitted(); $task->setSubmitted();
$this->getWorker($worker)->stack($task); $this->getWorker($worker)->stack($task);

View File

@ -23,7 +23,11 @@ declare(strict_types=1);
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pmmp\thread\Runnable;
use pmmp\thread\Thread as NativeThread;
use pmmp\thread\ThreadSafeArray;
use pocketmine\thread\NonThreadSafeValue; use pocketmine\thread\NonThreadSafeValue;
use function assert;
use function igbinary_serialize; use function igbinary_serialize;
use function igbinary_unserialize; use function igbinary_unserialize;
use function is_null; 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 * If you want to store non-thread-safe objects to access when the task completes, store them using
* {@link AsyncTask::storeLocal}. * {@link AsyncTask::storeLocal}.
*/ */
abstract class AsyncTask extends \ThreadedRunnable{ abstract class AsyncTask extends Runnable{
/** /**
* @var \ArrayObject|mixed[]|null object hash => mixed data * @var \ArrayObject|mixed[]|null object hash => mixed data
* @phpstan-var \ArrayObject<int, array<string, mixed>>|null * @phpstan-var \ArrayObject<int, array<string, mixed>>|null
@ -63,11 +67,8 @@ abstract class AsyncTask extends \ThreadedRunnable{
*/ */
private static ?\ArrayObject $threadLocalStorage = null; private static ?\ArrayObject $threadLocalStorage = null;
/** @var AsyncWorker|null $worker */ /** @phpstan-var ThreadSafeArray<int, string> */
public $worker = null; public ThreadSafeArray $progressUpdates;
/** @phpstan-var \ThreadedArray<int, string> */
public \ThreadedArray $progressUpdates;
/** @phpstan-var NonThreadSafeValue<mixed>|string|int|bool|float|null */ /** @phpstan-var NonThreadSafeValue<mixed>|string|int|bool|float|null */
private NonThreadSafeValue|string|int|bool|null|float $result = null; private NonThreadSafeValue|string|int|bool|null|float $result = null;
@ -85,12 +86,15 @@ abstract class AsyncTask extends \ThreadedRunnable{
$this->onRun(); $this->onRun();
}catch(\Throwable $e){ }catch(\Throwable $e){
$this->crashed = true; $this->crashed = true;
$this->worker->handleException($e);
\GlobalLogger::get()->logException($e);
} }
} }
$this->finished = true; $this->finished = true;
$this->worker->getNotifier()->wakeupSleeper(); $worker = NativeThread::getCurrentThread();
assert($worker instanceof AsyncWorker);
$worker->getNotifier()->wakeupSleeper();
} }
public function isCrashed() : bool{ public function isCrashed() : bool{

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pmmp\thread\Thread as NativeThread;
use pocketmine\snooze\SleeperNotifier; use pocketmine\snooze\SleeperNotifier;
use pocketmine\thread\Worker; use pocketmine\thread\Worker;
use function gc_enable; use function gc_enable;
@ -33,7 +34,7 @@ class AsyncWorker extends Worker{
private static array $store = []; private static array $store = [];
public function __construct( public function __construct(
private \ThreadedLogger $logger, private \ThreadSafeLogger $logger,
private int $id, private int $id,
private int $memoryLimit, private int $memoryLimit,
private SleeperNotifier $notifier private SleeperNotifier $notifier
@ -57,7 +58,7 @@ class AsyncWorker extends Worker{
} }
} }
public function getLogger() : \ThreadedLogger{ public function getLogger() : \ThreadSafeLogger{
return $this->logger; return $this->logger;
} }
@ -78,7 +79,7 @@ class AsyncWorker extends Worker{
* want to use on this worker thread from multiple AsyncTasks. * want to use on this worker thread from multiple AsyncTasks.
*/ */
public function saveToThreadStore(string $identifier, mixed $value) : void{ 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"); throw new \LogicException("Thread-local data can only be stored in the thread context");
} }
self::$store[$identifier] = $value; 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. * Objects stored in this storage may ONLY be retrieved while the task is running.
*/ */
public function getFromThreadStore(string $identifier) : mixed{ 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"); throw new \LogicException("Thread-local data can only be fetched in the thread context");
} }
return self::$store[$identifier] ?? null; 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. * Removes previously-stored mixed data from the worker's thread-local object store.
*/ */
public function removeFromThreadStore(string $identifier) : void{ 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"); throw new \LogicException("Thread-local data can only be removed in the thread context");
} }
unset(self::$store[$identifier]); unset(self::$store[$identifier]);

View File

@ -23,8 +23,10 @@ declare(strict_types=1);
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pmmp\thread\Thread as NativeThread;
use pocketmine\MemoryManager; use pocketmine\MemoryManager;
use Symfony\Component\Filesystem\Path; use Symfony\Component\Filesystem\Path;
use function assert;
/** /**
* Task used to dump memory from AsyncWorkers * Task used to dump memory from AsyncWorkers
@ -37,12 +39,14 @@ class DumpWorkerMemoryTask extends AsyncTask{
){} ){}
public function onRun() : void{ public function onRun() : void{
$worker = NativeThread::getCurrentThread();
assert($worker instanceof AsyncWorker);
MemoryManager::dumpMemory( MemoryManager::dumpMemory(
$this->worker, $worker,
Path::join($this->outputFolder, "AsyncWorker#" . $this->worker->getAsyncWorkerId()), Path::join($this->outputFolder, "AsyncWorker#" . $worker->getAsyncWorkerId()),
$this->maxNesting, $this->maxNesting,
$this->maxStringSize, $this->maxStringSize,
new \PrefixedLogger($this->worker->getLogger(), "Memory Dump") new \PrefixedLogger($worker->getLogger(), "Memory Dump")
); );
} }
} }

View File

@ -23,16 +23,17 @@ declare(strict_types=1);
namespace pocketmine\thread; namespace pocketmine\thread;
use pmmp\thread\ThreadSafeArray;
use pocketmine\errorhandler\ErrorToExceptionHandler; use pocketmine\errorhandler\ErrorToExceptionHandler;
use pocketmine\Server; use pocketmine\Server;
use function error_reporting; use function error_reporting;
trait CommonThreadPartsTrait{ trait CommonThreadPartsTrait{
/** /**
* @var \ThreadedArray|\ClassLoader[]|null * @var ThreadSafeArray|\ClassLoader[]|null
* @phpstan-var \ThreadedArray<int, \ClassLoader>|null * @phpstan-var ThreadSafeArray<int, \ClassLoader>|null
*/ */
private ?\ThreadedArray $classLoaders = null; private ?ThreadSafeArray $classLoaders = null;
protected ?string $composerAutoloaderPath = null; protected ?string $composerAutoloaderPath = null;
protected bool $isKilled = false; protected bool $isKilled = false;
@ -55,14 +56,15 @@ trait CommonThreadPartsTrait{
} }
if($this->classLoaders === null){ if($this->classLoaders === null){
$this->classLoaders = new \ThreadedArray(); $loaders = $this->classLoaders = new ThreadSafeArray();
}else{ }else{
$loaders = $this->classLoaders;
foreach($this->classLoaders as $k => $autoloader){ foreach($this->classLoaders as $k => $autoloader){
unset($this->classLoaders[$k]); unset($this->classLoaders[$k]);
} }
} }
foreach($autoloaders as $autoloader){ foreach($autoloaders as $autoloader){
$this->classLoaders[] = $autoloader; $loaders[] = $autoloader;
} }
} }

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\thread; namespace pocketmine\thread;
use pmmp\thread\ThreadSafe;
use function get_debug_type; use function get_debug_type;
use function igbinary_serialize; use function igbinary_serialize;
use function igbinary_unserialize; use function igbinary_unserialize;
@ -34,7 +35,7 @@ use function igbinary_unserialize;
* *
* @phpstan-template TValue * @phpstan-template TValue
*/ */
final class NonThreadSafeValue extends \ThreadedBase{ final class NonThreadSafeValue extends ThreadSafe{
private string $variable; private string $variable;
/** /**

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\thread; namespace pocketmine\thread;
use pmmp\thread\Thread as NativeThread;
use pocketmine\scheduler\AsyncTask; 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. * 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. * CPU.
* @see AsyncTask * @see AsyncTask
*/ */
abstract class Thread extends \Thread{ abstract class Thread extends NativeThread{
use CommonThreadPartsTrait; 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 //this is intentionally not traitified
ThreadManager::getInstance()->add($this); ThreadManager::getInstance()->add($this);

View File

@ -23,9 +23,11 @@ declare(strict_types=1);
namespace pocketmine\thread; namespace pocketmine\thread;
use pmmp\thread\ThreadSafe;
use pmmp\thread\ThreadSafeArray;
use function spl_object_id; use function spl_object_id;
class ThreadManager extends \ThreadedBase{ class ThreadManager extends ThreadSafe{
private static ?self $instance = null; private static ?self $instance = null;
@ -40,11 +42,11 @@ class ThreadManager extends \ThreadedBase{
return self::$instance; return self::$instance;
} }
/** @phpstan-var \ThreadedArray<int, Thread|Worker> */ /** @phpstan-var ThreadSafeArray<int, Thread|Worker> */
private \ThreadedArray $threads; private ThreadSafeArray $threads;
private function __construct(){ private function __construct(){
$this->threads = new \ThreadedArray(); $this->threads = new ThreadSafeArray();
} }
public function add(Worker|Thread $thread) : void{ public function add(Worker|Thread $thread) : void{

View File

@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\thread; namespace pocketmine\thread;
use pmmp\thread\Thread as NativeThread;
use pmmp\thread\Worker as NativeWorker;
use pocketmine\scheduler\AsyncTask; 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. * 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. * If you want to run tasks on other CPU cores, check out AsyncTask first.
* @see AsyncTask * @see AsyncTask
*/ */
abstract class Worker extends \Worker{ abstract class Worker extends NativeWorker{
use CommonThreadPartsTrait; 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 //this is intentionally not traitified
ThreadManager::getInstance()->add($this); ThreadManager::getInstance()->add($this);

View File

@ -24,14 +24,14 @@ declare(strict_types=1);
namespace pocketmine\utils; namespace pocketmine\utils;
use LogLevel; use LogLevel;
use pmmp\thread\Thread as NativeThread;
use pocketmine\thread\Thread; use pocketmine\thread\Thread;
use pocketmine\thread\Worker; use pocketmine\thread\Worker;
use function implode; use function implode;
use function sprintf; use function sprintf;
use const PHP_EOL; use const PHP_EOL;
use const PTHREADS_INHERIT_NONE;
class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ class MainLogger extends \AttachableThreadSafeLogger implements \BufferedLogger{
protected bool $logDebug; protected bool $logDebug;
private string $format = TextFormat::AQUA . "[%s] " . TextFormat::RESET . "%s[%s/%s]: %s" . TextFormat::RESET; 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->timezone = $timezone->getName();
$this->logWriterThread = new MainLoggerThread($logFile); $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{ public function shutdownLogWriterThread() : void{
if(\Thread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ if(NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){
$this->logWriterThread->shutdown(); $this->logWriterThread->shutdown();
}else{ }else{
throw new \LogicException("Only the creator thread can shutdown the logger thread"); 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{ protected function send(string $message, string $level, string $prefix, string $color) : void{
$time = new \DateTime('now', new \DateTimeZone($this->timezone)); $time = new \DateTime('now', new \DateTimeZone($this->timezone));
$thread = \Thread::getCurrentThread(); $thread = NativeThread::getCurrentThread();
if($thread === null){ if($thread === null){
$threadName = $this->mainThreadName . " thread"; $threadName = $this->mainThreadName . " thread";
}elseif($thread instanceof Thread || $thread instanceof Worker){ }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); $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL);
/** /**
* @var \ThreadedLoggerAttachment $attachment * @var \ThreadSafeLoggerAttachment $attachment
*/ */
foreach($this->attachments as $attachment){ foreach($this->attachments as $attachment){
$attachment->log($level, $message); $attachment->log($level, $message);
@ -208,7 +208,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{
} }
public function __destruct(){ public function __destruct(){
if(!$this->logWriterThread->isJoined() && \Thread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){ if(!$this->logWriterThread->isJoined() && NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){
$this->shutdownLogWriterThread(); $this->shutdownLogWriterThread();
} }
} }

View File

@ -23,22 +23,24 @@ declare(strict_types=1);
namespace pocketmine\utils; namespace pocketmine\utils;
use pmmp\thread\Thread;
use pmmp\thread\ThreadSafeArray;
use function fclose; use function fclose;
use function fopen; use function fopen;
use function fwrite; use function fwrite;
use function is_resource; use function is_resource;
use function touch; use function touch;
final class MainLoggerThread extends \Thread{ final class MainLoggerThread extends Thread{
/** @phpstan-var \ThreadedArray<int, string> */ /** @phpstan-var ThreadSafeArray<int, string> */
private \ThreadedArray $buffer; private ThreadSafeArray $buffer;
private bool $syncFlush = false; private bool $syncFlush = false;
private bool $shutdown = false; private bool $shutdown = false;
public function __construct( public function __construct(
private string $logFile private string $logFile
){ ){
$this->buffer = new \ThreadedArray(); $this->buffer = new ThreadSafeArray();
touch($this->logFile); touch($this->logFile);
} }

View File

@ -1,9 +1,11 @@
<?php <?php
namespace pmmp\thread;
/** /**
* @implements \IteratorAggregate<array-key, mixed> * @implements \IteratorAggregate<array-key, mixed>
*/ */
abstract class ThreadedBase implements \IteratorAggregate{ abstract class ThreadSafe implements \IteratorAggregate{
/** /**
* @template TReturn * @template TReturn
@ -17,9 +19,9 @@ abstract class ThreadedBase implements \IteratorAggregate{
/** /**
* @template TKey of array-key * @template TKey of array-key
* @template TValue * @template TValue
* @implements ArrayAccess<TKey, TValue> * @implements \ArrayAccess<TKey, TValue>
*/ */
final class ThreadedArray extends ThreadedBase implements Countable, ArrayAccess{ final class ThreadSafeArray extends ThreadSafe implements \Countable, \ArrayAccess{
/** /**
* @return TValue|null * @return TValue|null
@ -30,4 +32,4 @@ final class ThreadedArray extends ThreadedBase implements Countable, ArrayAccess
* @return TValue|null * @return TValue|null
*/ */
public function shift() : mixed{} public function shift() : mixed{}
} }