From 6f8f460a6c84f057013c74db8c47782ae4923b42 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 00:27:52 +0000 Subject: [PATCH] Partially revert "ConsoleReaderChildProcess: Commit suicide in more cases" This reverts commit cbe0f44c4f7bc3715acbf148f981bd93111c4c8f. This achieves the same result as the reverted commit wrt. process in the same manner (writing a keepalive into the socket and checking if it failed to send). However, it does _not_ allow the process to die on reaching pipe EOF, since this can cause many spams of subprocesses when stdin is actually not a tty (e.g. in a Docker container). --- src/console/ConsoleReader.php | 25 ++++++++++++++------ src/console/ConsoleReaderChildProcess.php | 9 +------- src/console/ConsoleReaderException.php | 28 ----------------------- 3 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 src/console/ConsoleReaderException.php diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index bd1fef4f5..6d7545fde 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,38 +23,49 @@ declare(strict_types=1); namespace pocketmine\console; -use pocketmine\utils\AssumptionFailedError; use function fclose; use function fgets; use function fopen; +use function is_resource; use function stream_select; use function trim; +use function usleep; final class ConsoleReader{ /** @var resource */ private $stdin; public function __construct(){ - $stdin = fopen("php://stdin", "r"); - if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); - $this->stdin = $stdin; + $this->initStdin(); + } + + private function initStdin() : void{ + if(is_resource($this->stdin)){ + fclose($this->stdin); + } + + $this->stdin = fopen("php://stdin", "r"); } /** * Reads a line from the console and adds it to the buffer. This method may block the thread. - * @throws ConsoleReaderException */ public function readLine() : ?string{ + if(!is_resource($this->stdin)){ + $this->initStdin(); + } + $r = [$this->stdin]; $w = $e = null; if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds return null; }elseif($count === false){ //stream error - throw new ConsoleReaderException("Unexpected EOF on select()"); + return null; } if(($raw = fgets($this->stdin)) === false){ //broken pipe or EOF - throw new ConsoleReaderException("Unexpected EOF on fgets()"); + usleep(200000); //prevent CPU waste if it's end of pipe + return null; //loop back round } $line = trim($raw); diff --git a/src/console/ConsoleReaderChildProcess.php b/src/console/ConsoleReaderChildProcess.php index 6f4a74258..509d0daca 100644 --- a/src/console/ConsoleReaderChildProcess.php +++ b/src/console/ConsoleReaderChildProcess.php @@ -45,14 +45,7 @@ if($socket === false){ } $consoleReader = new ConsoleReader(); while(!feof($socket)){ - try{ - $line = $consoleReader->readLine(); - }catch(ConsoleReaderException $e){ - //Encountered unexpected EOF. This might be because the user did something stupid, or because the parent process - //has died. In either case, commit suicide. If the parent process is still alive, it will start a new console - //reader. - break; - } + $line = $consoleReader->readLine(); if(@fwrite($socket, ($line ?? "") . "\n") === false){ //Always send even if there's no line, to check if the parent is alive //If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return diff --git a/src/console/ConsoleReaderException.php b/src/console/ConsoleReaderException.php deleted file mode 100644 index bf9e8fc67..000000000 --- a/src/console/ConsoleReaderException.php +++ /dev/null @@ -1,28 +0,0 @@ -