diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index 9da61cb6dd..c34be83c39 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,50 +23,37 @@ 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(){ - $this->initStdin(); - } - - private function initStdin() : void{ - if(is_resource($this->stdin)){ - fclose($this->stdin); - } - - $this->stdin = fopen("php://stdin", "r"); + $stdin = fopen("php://stdin", "r"); + if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); + $this->stdin = $stdin; } /** * 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 - $this->initStdin(); + throw new ConsoleReaderException("Unexpected EOF on select()"); } if(($raw = fgets($this->stdin)) === false){ //broken pipe or EOF - $this->initStdin(); - usleep(200000); //prevent CPU waste if it's end of pipe - return null; //loop back round + throw new ConsoleReaderException("Unexpected EOF on fgets()"); } $line = trim($raw); diff --git a/src/console/ConsoleReaderChildProcess.php b/src/console/ConsoleReaderChildProcess.php index 3879ecdff8..6f4a742584 100644 --- a/src/console/ConsoleReaderChildProcess.php +++ b/src/console/ConsoleReaderChildProcess.php @@ -45,8 +45,18 @@ if($socket === false){ } $consoleReader = new ConsoleReader(); while(!feof($socket)){ - $line = $consoleReader->readLine(); - if($line !== null){ - fwrite($socket, $line . "\n"); + 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; + } + 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 + //false even though the connection is actually broken. However, fwrite() will fail. + break; } } diff --git a/src/console/ConsoleReaderException.php b/src/console/ConsoleReaderException.php new file mode 100644 index 0000000000..bf9e8fc672 --- /dev/null +++ b/src/console/ConsoleReaderException.php @@ -0,0 +1,28 @@ +