diff --git a/composer.json b/composer.json index a2dc2a7f..ec2afdb1 100755 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "amphp/amp": "^2", "amphp/byte-stream": "^1.5", "amphp/parser": "^1", - "amphp/process": "^1", + "amphp/process": "dev-master as 1.0.2", "amphp/sync": "^1.0.1" }, "require-dev": { @@ -54,6 +54,12 @@ "php": "7.0.0" } }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/Ekstazi/process" + } + ], "scripts": { "check": [ "@cs", diff --git a/lib/Context/Context.php b/lib/Context/Context.php index c3d4a26f..2e4f9a36 100644 --- a/lib/Context/Context.php +++ b/lib/Context/Context.php @@ -31,4 +31,11 @@ public function kill(); * @throws \Amp\Parallel\Sync\PanicError If the context throws an uncaught exception. */ public function join(): Promise; + + /** + * Restarts the execution context. + * @param $force bool Whether to force restart or wait until finish first + * @return Promise + */ + public function restart($force = false): Promise; } diff --git a/lib/Context/Process.php b/lib/Context/Process.php index 10d43475..def1b6aa 100644 --- a/lib/Context/Process.php +++ b/lib/Context/Process.php @@ -358,4 +358,19 @@ public function kill() { $this->process->kill(); } + + /** + * {@inheritdoc} + */ + public function restart($force = false): Promise + { + return call(function () use ($force) { + if ($force) { + $this->kill(); + } else { + yield $this->join(); + } + yield $this->start(); + }); + } } diff --git a/lib/Context/Thread.php b/lib/Context/Thread.php index 6f644b48..9077b5d1 100644 --- a/lib/Context/Thread.php +++ b/lib/Context/Thread.php @@ -193,6 +193,7 @@ public function kill() } finally { $this->close(); } + $this->oid = 0; } } @@ -248,7 +249,7 @@ public function join(): Promise Loop::disable($this->watcher); $this->close(); } - + $this->oid = 0; return $response->getResult(); }); } @@ -308,4 +309,19 @@ public function send($data): Promise return $result; }); } + + /** + * {@inheritdoc} + */ + public function restart($force = false): Promise + { + return call(function () use ($force) { + if ($force) { + $this->kill(); + } else { + yield $this->join(); + } + yield $this->start(); + }); + } } diff --git a/lib/Worker/Internal/WorkerProcess.php b/lib/Worker/Internal/WorkerProcess.php index 39184e45..3416605e 100644 --- a/lib/Worker/Internal/WorkerProcess.php +++ b/lib/Worker/Internal/WorkerProcess.php @@ -60,4 +60,16 @@ public function join(): Promise { return $this->process->join(); } + + public function restart($force = false): Promise + { + return call(function () use ($force) { + if ($force) { + $this->kill(); + } else { + yield $this->join(); + } + return $this->start(); + }); + } } diff --git a/test/Context/AbstractContextTest.php b/test/Context/AbstractContextTest.php index a406f8f8..a1917668 100644 --- a/test/Context/AbstractContextTest.php +++ b/test/Context/AbstractContextTest.php @@ -66,26 +66,6 @@ public function testStartWhileRunningThrowsError() }); } - /** - * @expectedException \Amp\Parallel\Context\StatusError - */ - public function testStartMultipleTimesThrowsError() - { - $this->assertRunTimeGreaterThan(function () { - Loop::run(function () { - $context = $this->createContext(function () { - \sleep(1); - }); - - yield $context->start(); - yield $context->join(); - - yield $context->start(); - yield $context->join(); - }); - }, 2000); - } - /** * @expectedException \Amp\Parallel\Sync\PanicError */ @@ -308,4 +288,84 @@ public function testExitingContextOnSend() yield $context->send(\str_pad("", 1024 * 1024, "-")); }); } + + public function testStartAfterJoin() + { + $this->assertRunTimeGreaterThan(function () { + Loop::run(function () { + $context = $this->createContext(function () { + \usleep(100000); + }); + for ($i=0; $i<=1;$i++) { + $this->assertFalse($context->isRunning()); + + yield $context->start(); + + $this->assertTrue($context->isRunning()); + + yield $context->join(); + $this->assertFalse($context->isRunning()); + } + }); + }, 200); + } + + public function testStartAfterKill() + { + $this->assertRunTimeLessThan(function () { + Loop::run(function () { + $context = $this->createContext(function () { + \usleep(100000); + }); + for ($i=0; $i<=1;$i++) { + $this->assertFalse($context->isRunning()); + + yield $context->start(); + + $this->assertTrue($context->isRunning()); + + $this->assertRunTimeLessThan([$context, 'kill'], 1000); + $this->assertFalse($context->isRunning()); + } + }); + }, 200); + } + + public function testRestart() + { + $this->assertRunTimeGreaterThan(function () { + Loop::run(function () { + $context = $this->createContext(function () { + \usleep(100000); + }); + $this->assertFalse($context->isRunning()); + yield $context->start(); + + for ($i = 0; $i <= 1; $i++) { + $this->assertTrue($context->isRunning()); + + yield $context->restart(); + } + }); + }, 200); + } + + public function testForceRestart() + { + $this->assertRunTimeLessThan(function () { + Loop::run(function () { + $context = $this->createContext(function () { + \usleep(100000); + }); + $this->assertFalse($context->isRunning()); + yield $context->start(); + + for ($i = 0; $i <= 1; $i++) { + $this->assertTrue($context->isRunning()); + + yield $context->restart(true); + } + }); + }, 200); + } } diff --git a/test/Context/ProcessTest.php b/test/Context/ProcessTest.php index 17e3beef..7baffd79 100644 --- a/test/Context/ProcessTest.php +++ b/test/Context/ProcessTest.php @@ -84,4 +84,76 @@ public function testParseError() \var_dump(yield $process->join()); }); } + + public function testStartAfterJoin() + { + $this->assertRunTimeGreaterThan(function () { + Loop::run(function () { + $context = new Process(__DIR__ . "/wait-process.php"); + for ($i=0; $i<=1; $i++) { + $this->assertFalse($context->isRunning()); + + yield $context->start(); + + $this->assertTrue($context->isRunning()); + + yield $context->join(); + $this->assertFalse($context->isRunning()); + } + }); + }, 2000); + } + + public function testStartAfterKill() + { + $this->assertRunTimeLessThan(function () { + Loop::run(function () { + $context = new Process(__DIR__ . "/wait-process.php"); + for ($i=0; $i<=1;$i++) { + $this->assertFalse($context->isRunning()); + + yield $context->start(); + + $this->assertTrue($context->isRunning()); + + $this->assertRunTimeLessThan([$context, 'kill'], 1000); + $this->assertFalse($context->isRunning()); + } + }); + }, 2000); + } + + public function testRestart() + { + $this->assertRunTimeGreaterThan(function () { + Loop::run(function () { + $context = new Process(__DIR__ . "/wait-process.php"); + $this->assertFalse($context->isRunning()); + yield $context->start(); + + for ($i = 0; $i <= 1; $i++) { + $this->assertTrue($context->isRunning()); + + yield $context->restart(); + } + }); + }, 2000); + } + + public function testForceRestart() + { + $this->assertRunTimeLessThan(function () { + Loop::run(function () { + $context = new Process(__DIR__ . "/wait-process.php"); + $this->assertFalse($context->isRunning()); + yield $context->start(); + + for ($i = 0; $i <= 1; $i++) { + $this->assertTrue($context->isRunning()); + + yield $context->restart(true); + } + }); + }, 2000); + } } diff --git a/test/Context/wait-process.php b/test/Context/wait-process.php new file mode 100644 index 00000000..340ef3cb --- /dev/null +++ b/test/Context/wait-process.php @@ -0,0 +1,8 @@ +