From 7f795bc0411e22c116c411885158be14aa486c37 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sun, 22 Jun 2014 12:50:24 +0200 Subject: [PATCH] Fixed #1501 executing AsyncTasks blocks other threads --- src/pocketmine/Server.php | 39 +++++----- src/pocketmine/scheduler/AsyncTask.php | 24 +++--- src/pocketmine/scheduler/AsyncWorker.php | 7 +- src/pocketmine/scheduler/ServerScheduler.php | 2 +- src/pocketmine/scheduler/TickScheduler.php | 80 -------------------- 5 files changed, 42 insertions(+), 110 deletions(-) delete mode 100644 src/pocketmine/scheduler/TickScheduler.php diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index d847c9033..e45ff806f 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -42,7 +42,6 @@ use pocketmine\level\format\LevelProviderManager; use pocketmine\level\generator\GenerationRequestManager; use pocketmine\level\generator\Generator; use pocketmine\level\Level; - use pocketmine\metadata\EntityMetadataStore; use pocketmine\metadata\LevelMetadataStore; use pocketmine\metadata\PlayerMetadataStore; @@ -69,9 +68,9 @@ use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginLoadOrder; use pocketmine\plugin\PluginManager; use pocketmine\scheduler\CallbackTask; +use pocketmine\scheduler\ExampleTask; use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\ServerScheduler; -use pocketmine\scheduler\TickScheduler; use pocketmine\tile\Tile; use pocketmine\updater\AutoUpdater; use pocketmine\utils\Binary; @@ -118,8 +117,16 @@ class Server{ /** @var GenerationRequestManager */ private $generationManager = null; - /** @var TickScheduler */ - private $tickScheduler = null; + /** + * Counts the ticks since the server start + * + * @var int + */ + private $tickCounter; + private $nextTick = 0; + private $tickMeasure = 20; + private $tickTime = 0; + private $inTick = false; /** @var \Logger */ private $logger; @@ -151,14 +158,6 @@ class Server{ /** @var LevelMetadataStore */ private $levelMetadata; - /** - * Counts the ticks since the server start - * - * @var int - */ - private $tickCounter; - private $inTick = false; - /** @var SourceInterface[] */ private $interfaces = []; @@ -525,7 +524,7 @@ class Server{ * @return float */ public function getTicksPerSecond(){ - return $this->tickScheduler->getTPS(); + return round((0.05 / $this->tickMeasure) * 20, 2); } /** @@ -1323,7 +1322,6 @@ class Server{ $this->banByIP = new BanList($this->dataPath . "banned-ips.txt"); $this->banByIP->load(); - $this->tickScheduler = new TickScheduler(20); $this->scheduler = new ServerScheduler(); $this->console = new CommandReader(); @@ -1640,7 +1638,6 @@ class Server{ $this->properties->save(); - $this->tickScheduler->kill(); $this->console->kill(); foreach($this->interfaces as $interface){ $interface->shutdown(); @@ -1682,6 +1679,7 @@ class Server{ $this->logger->info("Default game type: " . self::getGamemodeString($this->getGamemode())); //TODO: string name $this->logger->info("Done (" . round(microtime(true) - \pocketmine\START_TIME, 3) . 's)! For help, type "help" or "?"'); + $this->scheduler->scheduleAsyncTask(new ExampleTask()); if(Utils::getOS() === "win"){ //Workaround less usleep() waste $this->tickProcessorWindows(); }else{ @@ -1929,7 +1927,12 @@ class Server{ * Tries to execute a server tick */ public function tick(){ - if($this->inTick === false and $this->tickScheduler->hasTick()){ + if($this->inTick === false){ + $tickTime = microtime(true); + if($tickTime < $this->nextTick){ + return false; + } + $this->inTick = true; //Fix race conditions ++$this->tickCounter; @@ -1944,7 +1947,9 @@ class Server{ } } - $this->tickScheduler->doTick(); + $this->tickMeasure = (($time = microtime(true)) - $this->tickTime); + $this->tickTime = $time; + $this->nextTick = 0.05 * (0.05 / max(0.05, $this->tickMeasure)) + $time; $this->inTick = false; return true; diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index a357badc5..fa0f03f48 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -33,19 +33,30 @@ abstract class AsyncTask extends \Threaded{ private $result; public function run(){ - $this->lock(); + $this->finished = false; + $this->complete = false; $this->result = null; $this->onRun(); $this->finished = true; $this->complete = $this->result === null ? true : false; - $this->unlock(); } /** * @return bool */ public function isCompleted(){ - return $this->complete === true; + return $this->synchronized(function(){ + return $this->complete === true; + }); + } + + /** + * @return bool + */ + public function isFinished(){ + return $this->synchronized(function(){ + return $this->finished === true; + }); } /** @@ -73,13 +84,6 @@ abstract class AsyncTask extends \Threaded{ $this->result = @serialize($result); } - /** - * @return bool - */ - public function isFinished(){ - return $this->finished === true; - } - /** * Actions to execute when run * diff --git a/src/pocketmine/scheduler/AsyncWorker.php b/src/pocketmine/scheduler/AsyncWorker.php index a22559a50..8d4c91578 100644 --- a/src/pocketmine/scheduler/AsyncWorker.php +++ b/src/pocketmine/scheduler/AsyncWorker.php @@ -24,10 +24,13 @@ namespace pocketmine\scheduler; class AsyncWorker extends \Worker{ public $path; - public function start($options = PTHREADS_INHERIT_CLASSES){ + public function __construct(){ $this->path = \pocketmine\PATH; + return parent::start(PTHREADS_INHERIT_ALL & ~PTHREADS_INHERIT_CLASSES); + } + + public function start(){ - return parent::start($options & ~PTHREADS_INHERIT_CLASSES); } public function run(){ diff --git a/src/pocketmine/scheduler/ServerScheduler.php b/src/pocketmine/scheduler/ServerScheduler.php index 7fa22896c..fc70c8f3f 100644 --- a/src/pocketmine/scheduler/ServerScheduler.php +++ b/src/pocketmine/scheduler/ServerScheduler.php @@ -236,4 +236,4 @@ class ServerScheduler{ return $this->ids++; } -} +} \ No newline at end of file diff --git a/src/pocketmine/scheduler/TickScheduler.php b/src/pocketmine/scheduler/TickScheduler.php deleted file mode 100644 index 4a3ad3253..000000000 --- a/src/pocketmine/scheduler/TickScheduler.php +++ /dev/null @@ -1,80 +0,0 @@ -ticksPerSecond = (int) $ticksPerSecond; - $this->sleepTime = (int) (1000000 / $this->ticksPerSecond); - $this->tickMeasure = $this->sleepTime; - $this->start(PTHREADS_INHERIT_ALL & ~PTHREADS_INHERIT_CLASSES); - } - - /** - * Returns true if clear to run tick - * - * @return bool - */ - public function hasTick(){ - return $this->synchronized(function (){ - $hasTick = $this->hasTick; - $this->hasTick = false; - - return $hasTick === true; - }); - } - - public function doTick(){ - $this->notify(); - } - - /** - * @return float - */ - public function getTPS(){ - return $this->synchronized(function (){ - return round(($this->sleepTime / $this->tickMeasure) * $this->ticksPerSecond, 2); - }); - } - - public function run(){ - $tickTime = microtime(true); - $this->tickMeasure = $this->sleepTime; - while(true){ - $this->synchronized(function (){ - $this->hasTick = true; - $this->wait(); - $this->hasTick = false; - }); - - $this->tickMeasure = (int) ((($time = microtime(true)) - $tickTime) * 1000000); - $tickTime = $time; - $sleepTime = $this->sleepTime * ($this->sleepTime / max($this->sleepTime, $this->tickMeasure)); - usleep((int) $sleepTime); - } - } -} \ No newline at end of file