From 17341d7406257f3ee641f83555df82d1549b2792 Mon Sep 17 00:00:00 2001 From: HimbeersaftLP Date: Fri, 26 Jul 2019 19:49:02 +0200 Subject: [PATCH 1/9] Load Mathjax from https to prevent unsafe scripts error (#3058) --- doxygen/doxygen.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/doxygen.conf b/doxygen/doxygen.conf index 371218ece..c65220fb3 100644 --- a/doxygen/doxygen.conf +++ b/doxygen/doxygen.conf @@ -1565,7 +1565,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example From 581eeee01de72ab6d85a10620e6ed8490acdcf26 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:14:45 +0100 Subject: [PATCH 2/9] fix rogue @package doc making doxygen choke --- src/pocketmine/scheduler/BulkCurlTask.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pocketmine/scheduler/BulkCurlTask.php b/src/pocketmine/scheduler/BulkCurlTask.php index 268fe916e..1ab6faeb0 100644 --- a/src/pocketmine/scheduler/BulkCurlTask.php +++ b/src/pocketmine/scheduler/BulkCurlTask.php @@ -32,8 +32,6 @@ use function unserialize; * Executes a consecutive list of cURL operations. * * The result of this AsyncTask is an array of arrays (returned from {@link Utils::simpleCurl}) or InternetException objects. - * - * @package pocketmine\scheduler */ class BulkCurlTask extends AsyncTask{ private $operations; From 99f65f19ac6a6cc3da1ee4480993c973b98a6dec Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:18:09 +0100 Subject: [PATCH 3/9] BulkCurlTask: point to the right place in docs --- src/pocketmine/scheduler/BulkCurlTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/BulkCurlTask.php b/src/pocketmine/scheduler/BulkCurlTask.php index 1ab6faeb0..56fc3aa5b 100644 --- a/src/pocketmine/scheduler/BulkCurlTask.php +++ b/src/pocketmine/scheduler/BulkCurlTask.php @@ -31,7 +31,7 @@ use function unserialize; /** * Executes a consecutive list of cURL operations. * - * The result of this AsyncTask is an array of arrays (returned from {@link Utils::simpleCurl}) or InternetException objects. + * The result of this AsyncTask is an array of arrays (returned from {@link Internet::simpleCurl}) or InternetException objects. */ class BulkCurlTask extends AsyncTask{ private $operations; From d55889d85fbc9ea459de55ccc684a9197b878ad6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:41:45 +0100 Subject: [PATCH 4/9] AsyncTask: fixing docs --- src/pocketmine/scheduler/AsyncTask.php | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index 9da2c82b2..b34cc34f2 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -34,12 +34,12 @@ use function unserialize; * * An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker * with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that - * run for a long time or infinitely, start another {@link \pocketmine\Thread} instead. + * run for a long time or infinitely, start another thread instead. * * 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 - * {@link AsyncTask#storeLocal}. + * {@link AsyncTask::storeLocal}. * * WARNING: As of pthreads v3.1.6, 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. @@ -185,8 +185,8 @@ abstract class AsyncTask extends Collectable{ } /** - * Call this method from {@link AsyncTask#onRun} (AsyncTask execution thread) to schedule a call to - * {@link AsyncTask#onProgressUpdate} from the main thread with the given progress parameter. + * Call this method from {@link AsyncTask::onRun} (AsyncTask execution thread) to schedule a call to + * {@link AsyncTask::onProgressUpdate} from the main thread with the given progress parameter. * * @param mixed $progress A value that can be safely serialize()'ed. */ @@ -207,12 +207,12 @@ abstract class AsyncTask extends Collectable{ } /** - * Called from the main thread after {@link AsyncTask#publishProgress} is called. - * All {@link AsyncTask#publishProgress} calls should result in {@link AsyncTask#onProgressUpdate} calls before - * {@link AsyncTask#onCompletion} is called. + * Called from the main thread after {@link AsyncTask::publishProgress} is called. + * All {@link AsyncTask::publishProgress} calls should result in {@link AsyncTask::onProgressUpdate} calls before + * {@link AsyncTask::onCompletion} is called. * * @param Server $server - * @param mixed $progress The parameter passed to {@link AsyncTask#publishProgress}. It is serialize()'ed + * @param mixed $progress The parameter passed to {@link AsyncTask::publishProgress}. It is serialize()'ed * and then unserialize()'ed, as if it has been cloned. */ public function onProgressUpdate(Server $server, $progress){ @@ -221,20 +221,20 @@ abstract class AsyncTask extends Collectable{ /** * Saves mixed data in thread-local storage on the parent thread. You may use this to retain references to objects - * or arrays which you need to access in {@link AsyncTask#onCompletion} which cannot be stored as a property of + * or arrays which you need to access in {@link AsyncTask::onCompletion} which cannot be stored as a property of * your task (due to them becoming serialized). * * Scalar types can be stored directly in class properties instead of using this storage. * - * Objects stored in this storage MUST be retrieved through {@link #fetchLocal} when {@link #onCompletion} is called. + * Objects stored in this storage MUST be retrieved through {@link AsyncTask::fetchLocal} when {@link AsyncTask::onCompletion} is called. * Otherwise, a NOTICE level message will be raised and the reference will be removed after onCompletion exits. * * WARNING: Use this method carefully. It might take a long time before an AsyncTask is completed. PocketMine will * keep a strong reference to objects passed in this method. This may result in a light memory leak. Usually this * does not cause memory failure, but be aware that the object may be no longer usable when the AsyncTask completes. - * (E.g. a {@link \pocketmine\Level} object is no longer usable because it is unloaded while the AsyncTask is - * executing, or even a plugin might be unloaded). Since PocketMine keeps a strong reference, the objects are still - * valid, but the implementation is responsible for checking whether these objects are still usable. + * (E.g. a Level object is no longer usable because it is unloaded while the AsyncTask is executing, or even a + * plugin might be unloaded). Since PocketMine keeps a strong reference, the objects are still valid, but the + * implementation is responsible for checking whether these objects are still usable. * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! * @@ -259,13 +259,13 @@ abstract class AsyncTask extends Collectable{ /** * Returns and removes mixed data in thread-local storage on the parent thread. Call this method from - * {@link AsyncTask#onCompletion} to fetch the data stored in the object store, if any. + * {@link AsyncTask::onCompletion} to fetch the data stored in the object store, if any. * * If no data was stored in the local store, or if the data was already retrieved by a previous call to fetchLocal, * do NOT call this method, or an exception will be thrown. * - * Do not call this method from {@link AsyncTask#onProgressUpdate}, because this method deletes stored data, which - * means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask#peekLocal} instead to + * Do not call this method from {@link AsyncTask::onProgressUpdate}, because this method deletes stored data, which + * means that you will not be able to retrieve it again afterwards. Use {@link AsyncTask::peekLocal} instead to * retrieve stored data without removing it from the store. * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! @@ -287,11 +287,11 @@ abstract class AsyncTask extends Collectable{ /** * Returns mixed data in thread-local storage on the parent thread **without clearing** it. Call this method from - * {@link AsyncTask#onProgressUpdate} to fetch the data stored if you need to be able to access the data later on, + * {@link AsyncTask::onProgressUpdate} to fetch the data stored if you need to be able to access the data later on, * such as in another progress update. * - * Use {@link AsyncTask#fetchLocal} instead from {@link AsyncTask#onCompletion}, because this method does not delete - * the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask#onCompletion} + * Use {@link AsyncTask::fetchLocal} instead from {@link AsyncTask::onCompletion}, because this method does not delete + * the data, and not clearing the data will result in a warning for memory leak after {@link AsyncTask::onCompletion} * finished executing. * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! From 95dfff727eb195c92de50ab11d6ce74eedb6bda9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:47:03 +0100 Subject: [PATCH 5/9] Wrap PocketMine.php body inside a function this isolates variables from the global scope and also prevents doxygen documenting these variables. --- src/pocketmine/PocketMine.php | 314 +++++++++++++++++----------------- 1 file changed, 159 insertions(+), 155 deletions(-) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 0e2b306de..90292b77d 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -121,176 +121,180 @@ namespace pocketmine { return $messages; } - if(!empty($messages = check_platform_dependencies())){ - echo PHP_EOL; - $binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown"; - critical_error("Selected PHP binary ($binary) does not satisfy some requirements."); - foreach($messages as $m){ - echo " - $m" . PHP_EOL; - } - critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html."); - echo PHP_EOL; - exit(1); - } - unset($messages); - - error_reporting(-1); - - if(\Phar::running(true) !== ""){ - define('pocketmine\PATH', \Phar::running(true) . "/"); - }else{ - define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR); - } - - $opts = getopt("", ["bootstrap:"]); - if(isset($opts["bootstrap"])){ - $bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"]; - }else{ - $bootstrap = \pocketmine\PATH . 'vendor/autoload.php'; - } - define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap); - - if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){ - require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH); - }else{ - critical_error("Composer autoloader not found at " . $bootstrap); - critical_error("Please install/update Composer dependencies or use provided builds."); - exit(1); - } - - set_error_handler([Utils::class, 'errorExceptionHandler']); - - /* - * We now use the Composer autoloader, but this autoloader is still for loading plugins. - */ - $autoloader = new \BaseClassLoader(); - $autoloader->register(false); - - set_time_limit(0); //Who set it to 30 seconds?!?! - - ini_set("allow_url_fopen", '1'); - ini_set("display_errors", '1'); - ini_set("display_startup_errors", '1'); - ini_set("default_charset", "utf-8"); - - ini_set("memory_limit", '-1'); - - define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR); - - $opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]); - - define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR); - define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR); - - if(!file_exists(\pocketmine\DATA)){ - mkdir(\pocketmine\DATA, 0777, true); - } - - define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock'); - define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b")); - if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){ - //wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the - //other server wrote its PID and released exclusive lock before we get our lock - flock(\pocketmine\LOCK_FILE, LOCK_SH); - $pid = stream_get_contents(\pocketmine\LOCK_FILE); - critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ")."); - critical_error("Please stop the other server first before running a new one."); - exit(1); - } - ftruncate(\pocketmine\LOCK_FILE, 0); - fwrite(\pocketmine\LOCK_FILE, (string) getmypid()); - fflush(\pocketmine\LOCK_FILE); - flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading - - //Logger has a dependency on timezone - $tzError = Timezone::init(); - - if(isset($opts["enable-ansi"])){ - Terminal::init(true); - }elseif(isset($opts["disable-ansi"])){ - Terminal::init(false); - }else{ - Terminal::init(); - } - - $logger = new MainLogger(\pocketmine\DATA . "server.log"); - $logger->registerStatic(); - - foreach($tzError as $e){ - $logger->warning($e); - } - unset($tzError); - - if(extension_loaded("xdebug")){ - $logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL); - } - if(!extension_loaded("pocketmine_chunkutils")){ - $logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance."); - } - - if(\Phar::running(true) === ""){ - $logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance."); - } - - $version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER); - define('pocketmine\VERSION', $version->getFullVersion(true)); - - $gitHash = str_repeat("00", 20); - - if(\Phar::running(true) === ""){ - if(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ - $gitHash = trim($out); - if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified - $gitHash .= "-dirty"; + function server(){ + if(!empty($messages = check_platform_dependencies())){ + echo PHP_EOL; + $binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown"; + critical_error("Selected PHP binary ($binary) does not satisfy some requirements."); + foreach($messages as $m){ + echo " - $m" . PHP_EOL; } + critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html."); + echo PHP_EOL; + exit(1); } - }else{ - $phar = new \Phar(\Phar::running(false)); - $meta = $phar->getMetadata(); - if(isset($meta["git"])){ - $gitHash = $meta["git"]; + unset($messages); + + error_reporting(-1); + + if(\Phar::running(true) !== ""){ + define('pocketmine\PATH', \Phar::running(true) . "/"); + }else{ + define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR); } - } - define('pocketmine\GIT_COMMIT', $gitHash); + $opts = getopt("", ["bootstrap:"]); + if(isset($opts["bootstrap"])){ + $bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"]; + }else{ + $bootstrap = \pocketmine\PATH . 'vendor/autoload.php'; + } + define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap); + if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){ + require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH); + }else{ + critical_error("Composer autoloader not found at " . $bootstrap); + critical_error("Please install/update Composer dependencies or use provided builds."); + exit(1); + } - @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1); - @ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors + set_error_handler([Utils::class, 'errorExceptionHandler']); - $exitCode = 0; - do{ - if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){ - $installer = new SetupWizard(); - if(!$installer->run()){ - $exitCode = -1; - break; + /* + * We now use the Composer autoloader, but this autoloader is still for loading plugins. + */ + $autoloader = new \BaseClassLoader(); + $autoloader->register(false); + + set_time_limit(0); //Who set it to 30 seconds?!?! + + ini_set("allow_url_fopen", '1'); + ini_set("display_errors", '1'); + ini_set("display_startup_errors", '1'); + ini_set("default_charset", "utf-8"); + + ini_set("memory_limit", '-1'); + + define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR); + + $opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]); + + define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR); + define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR); + + if(!file_exists(\pocketmine\DATA)){ + mkdir(\pocketmine\DATA, 0777, true); + } + + define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock'); + define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b")); + if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){ + //wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the + //other server wrote its PID and released exclusive lock before we get our lock + flock(\pocketmine\LOCK_FILE, LOCK_SH); + $pid = stream_get_contents(\pocketmine\LOCK_FILE); + critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ")."); + critical_error("Please stop the other server first before running a new one."); + exit(1); + } + ftruncate(\pocketmine\LOCK_FILE, 0); + fwrite(\pocketmine\LOCK_FILE, (string) getmypid()); + fflush(\pocketmine\LOCK_FILE); + flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading + + //Logger has a dependency on timezone + $tzError = Timezone::init(); + + if(isset($opts["enable-ansi"])){ + Terminal::init(true); + }elseif(isset($opts["disable-ansi"])){ + Terminal::init(false); + }else{ + Terminal::init(); + } + + $logger = new MainLogger(\pocketmine\DATA . "server.log"); + $logger->registerStatic(); + + foreach($tzError as $e){ + $logger->warning($e); + } + unset($tzError); + + if(extension_loaded("xdebug")){ + $logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL); + } + if(!extension_loaded("pocketmine_chunkutils")){ + $logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance."); + } + + if(\Phar::running(true) === ""){ + $logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance."); + } + + $version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER); + define('pocketmine\VERSION', $version->getFullVersion(true)); + + $gitHash = str_repeat("00", 20); + + if(\Phar::running(true) === ""){ + if(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ + $gitHash = trim($out); + if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified + $gitHash .= "-dirty"; + } + } + }else{ + $phar = new \Phar(\Phar::running(false)); + $meta = $phar->getMetadata(); + if(isset($meta["git"])){ + $gitHash = $meta["git"]; } } - //TODO: move this to a Server field - define('pocketmine\START_TIME', microtime(true)); - ThreadManager::init(); - new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH); + define('pocketmine\GIT_COMMIT', $gitHash); - $logger->info("Stopping other threads"); - $killer = new ServerKiller(8); - $killer->start(PTHREADS_INHERIT_NONE); - usleep(10000); //Fixes ServerKiller not being able to start on single-core machines + @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1); + @ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors - if(ThreadManager::getInstance()->stopAll() > 0){ - if(\pocketmine\DEBUG > 1){ - echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; + $exitCode = 0; + do{ + if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){ + $installer = new SetupWizard(); + if(!$installer->run()){ + $exitCode = -1; + break; + } } - Utils::kill(getmypid()); - } - }while(false); - $logger->shutdown(); - $logger->join(); + //TODO: move this to a Server field + define('pocketmine\START_TIME', microtime(true)); + ThreadManager::init(); + new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH); - echo Terminal::$FORMAT_RESET . PHP_EOL; + $logger->info("Stopping other threads"); - exit($exitCode); + $killer = new ServerKiller(8); + $killer->start(PTHREADS_INHERIT_NONE); + usleep(10000); //Fixes ServerKiller not being able to start on single-core machines + + if(ThreadManager::getInstance()->stopAll() > 0){ + if(\pocketmine\DEBUG > 1){ + echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; + } + Utils::kill(getmypid()); + } + }while(false); + + $logger->shutdown(); + $logger->join(); + + echo Terminal::$FORMAT_RESET . PHP_EOL; + + exit($exitCode); + } + + \pocketmine\server(); } From cb247a5f28958e4af48ad3897fb3c222e76ecf44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Jul 2019 19:52:26 +0100 Subject: [PATCH 6/9] AsyncTask: Deprecate methods removed in 2c4f2810d2654375c2b834fe12999b465bfa2caf --- src/pocketmine/scheduler/AsyncTask.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index b34cc34f2..0edd4cef4 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -127,6 +127,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::getFromThreadStore() * * @param string $identifier @@ -141,6 +142,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::saveToThreadStore() * * @param string $identifier @@ -154,6 +156,7 @@ abstract class AsyncTask extends Collectable{ } /** + * @deprecated * @see AsyncWorker::removeFromThreadStore() * * @param string $identifier From e75a08a5a381f511cfea56e63417237159cfa1af Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jul 2019 14:39:40 +0100 Subject: [PATCH 7/9] AsyncPool: ensure TLS is always cleaned on task removal, closes #3059 --- src/pocketmine/scheduler/AsyncPool.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index cd91319ed..8174b230c 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -248,6 +248,7 @@ class AsyncPool{ $this->workerUsage[$this->taskWorkers[$task->getTaskId()]]--; } + $task->removeDanglingStoredObjects(); unset($this->tasks[$task->getTaskId()]); unset($this->taskWorkers[$task->getTaskId()]); } From 6566dd8c8fa40d88b5484df414147d407d4ae6e4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jul 2019 14:44:40 +0100 Subject: [PATCH 8/9] AsyncPool: Remove useless warning about complex data leftovers this is automatically cleaned up anyway, so this warning is just redundant noise. --- src/pocketmine/scheduler/AsyncPool.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index 8174b230c..a0b6200b0 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -28,7 +28,6 @@ use pocketmine\utils\Utils; use function array_keys; use function assert; use function count; -use function get_class; use function spl_object_hash; use function time; use const PHP_INT_MAX; @@ -318,9 +317,6 @@ class AsyncPool{ */ $task->checkProgressUpdates($this->server); $task->onCompletion($this->server); - if($task->removeDanglingStoredObjects()){ - $this->logger->notice("AsyncTask " . get_class($task) . " stored local complex data but did not remove them after completion"); - } } $this->removeTask($task); From cb40484a2ec91e124c41cb05b1dc561ef9fd25e1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Jul 2019 14:52:53 +0100 Subject: [PATCH 9/9] AsyncTask: Remove a bunch of reference-management drivel from documentation of storeLocal() this works (mostly) the same way regular properties do, so the usual rules are implied. --- src/pocketmine/scheduler/AsyncTask.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index b34cc34f2..d0158eb20 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -229,13 +229,6 @@ abstract class AsyncTask extends Collectable{ * Objects stored in this storage MUST be retrieved through {@link AsyncTask::fetchLocal} when {@link AsyncTask::onCompletion} is called. * Otherwise, a NOTICE level message will be raised and the reference will be removed after onCompletion exits. * - * WARNING: Use this method carefully. It might take a long time before an AsyncTask is completed. PocketMine will - * keep a strong reference to objects passed in this method. This may result in a light memory leak. Usually this - * does not cause memory failure, but be aware that the object may be no longer usable when the AsyncTask completes. - * (E.g. a Level object is no longer usable because it is unloaded while the AsyncTask is executing, or even a - * plugin might be unloaded). Since PocketMine keeps a strong reference, the objects are still valid, but the - * implementation is responsible for checking whether these objects are still usable. - * * WARNING: THIS METHOD SHOULD ONLY BE CALLED FROM THE MAIN THREAD! * * @param mixed $complexData the data to store