diff --git a/.gitattributes b/.gitattributes
index 27b765f..f11271b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
/tests export-ignore
/.github export-ignore
+/types export-ignore
diff --git a/.github/workflows/close-pull-request.yml b/.github/workflows/close-pull-request.yml
index 591822c..4cbca96 100644
--- a/.github/workflows/close-pull-request.yml
+++ b/.github/workflows/close-pull-request.yml
@@ -2,12 +2,8 @@ name: Close Pull Request
on:
pull_request_target:
- types: [opened]
+ types: [ opened ]
jobs:
run:
- runs-on: ubuntu-latest
- steps:
- - uses: superbrothers/close-pull-request@v3
- with:
- comment: "Hi, this is a READ-ONLY repository, please submit your PR on the https://github.com/hyperf/hyperf repository.
This Pull Request will close automatically.
Thanks! "
+ uses: hyperf/.github/.github/workflows/close-pull-request.yml@master
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4ebb5d0..8ec4a62 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,18 +8,4 @@ name: Release
jobs:
release:
- name: Release
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
- - name: Create Release
- id: create_release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ github.ref }}
- release_name: Release ${{ github.ref }}
- draft: false
- prerelease: false
+ uses: hyperf/.github/.github/workflows/release.yml@master
diff --git a/composer.json b/composer.json
index 1d60f65..202a79e 100644
--- a/composer.json
+++ b/composer.json
@@ -10,16 +10,16 @@
],
"homepage": "https://hyperf.io",
"support": {
- "docs": "https://hyperf.wiki",
"issues": "https://github.com/hyperf/hyperf/issues",
- "pull-request": "https://github.com/hyperf/hyperf/pulls",
- "source": "https://github.com/hyperf/hyperf"
+ "source": "https://github.com/hyperf/hyperf",
+ "docs": "https://hyperf.wiki",
+ "pull-request": "https://github.com/hyperf/hyperf/pulls"
},
"require": {
- "php": ">=8.0",
- "hyperf/context": "~3.0.0",
- "hyperf/contract": "~3.0.0",
- "hyperf/engine": "^1.2|^2.0"
+ "php": ">=8.1",
+ "hyperf/context": "~3.1.0",
+ "hyperf/contract": "~3.1.0",
+ "hyperf/engine": "^2.14.0"
},
"autoload": {
"psr-4": {
@@ -39,7 +39,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
}
}
diff --git a/src/Barrier.php b/src/Barrier.php
new file mode 100644
index 0000000..b01182a
--- /dev/null
+++ b/src/Barrier.php
@@ -0,0 +1,17 @@
+getId();
- } catch (\Throwable) {
+ } catch (Throwable) {
return -1;
}
}
+ /**
+ * Create a coroutine with a copy of the parent coroutine context.
+ */
+ public static function fork(callable $callable, array $keys = []): int
+ {
+ $cid = static::id();
+ $callable = static function () use ($callable, $cid, $keys) {
+ Context::copy($cid, $keys);
+ $callable();
+ };
+
+ return static::create($callable);
+ }
+
public static function inCoroutine(): bool
{
return Co::id() > 0;
@@ -93,6 +119,14 @@ public static function exists(int $id): bool
return Co::exists($id);
}
+ /**
+ * @return iterable
+ */
+ public static function list(): iterable
+ {
+ return Co::list();
+ }
+
private static function printLog(Throwable $throwable): void
{
if (ApplicationContext::hasContainer()) {
diff --git a/src/Exception/ChannelClosedException.php b/src/Exception/ChannelClosedException.php
index a90c444..d352918 100644
--- a/src/Exception/ChannelClosedException.php
+++ b/src/Exception/ChannelClosedException.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
use RuntimeException;
diff --git a/src/Exception/ExceptionThrower.php b/src/Exception/ExceptionThrower.php
index 5b2f94e..4568efc 100644
--- a/src/Exception/ExceptionThrower.php
+++ b/src/Exception/ExceptionThrower.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
use Throwable;
diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php
index c9b8614..0676d71 100644
--- a/src/Exception/InvalidArgumentException.php
+++ b/src/Exception/InvalidArgumentException.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
class InvalidArgumentException extends \InvalidArgumentException
diff --git a/src/Exception/ParallelExecutionException.php b/src/Exception/ParallelExecutionException.php
index c674dca..304a43d 100644
--- a/src/Exception/ParallelExecutionException.php
+++ b/src/Exception/ParallelExecutionException.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
use RuntimeException;
diff --git a/src/Exception/TimeoutException.php b/src/Exception/TimeoutException.php
index fae8576..77e353c 100644
--- a/src/Exception/TimeoutException.php
+++ b/src/Exception/TimeoutException.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
use RuntimeException;
diff --git a/src/Exception/WaitTimeoutException.php b/src/Exception/WaitTimeoutException.php
index 8393231..1ad1296 100644
--- a/src/Exception/WaitTimeoutException.php
+++ b/src/Exception/WaitTimeoutException.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine\Exception;
class WaitTimeoutException extends TimeoutException
diff --git a/src/Functions.php b/src/Functions.php
index e4c97ac..35ded47 100644
--- a/src/Functions.php
+++ b/src/Functions.php
@@ -9,11 +9,13 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine;
use Closure;
use Hyperf\Context\ApplicationContext;
use RuntimeException;
+use Swoole\Runtime;
/**
* @param callable[] $callables
@@ -28,6 +30,12 @@ function parallel(array $callables, int $concurrent = 0): array
return $parallel->wait();
}
+/**
+ * @template TReturn
+ *
+ * @param Closure():TReturn $closure
+ * @return TReturn
+ */
function wait(Closure $closure, ?float $timeout = null)
{
if (ApplicationContext::hasContainer()) {
@@ -65,11 +73,11 @@ function run($callbacks, int $flags = SWOOLE_HOOK_ALL): bool
throw new RuntimeException('Function \'run\' only execute in non-coroutine environment.');
}
- \Swoole\Runtime::enableCoroutine($flags);
+ Runtime::enableCoroutine($flags);
/* @phpstan-ignore-next-line */
$result = \Swoole\Coroutine\run(...(array) $callbacks);
- \Swoole\Runtime::enableCoroutine(false);
+ Runtime::enableCoroutine(0);
return $result;
}
diff --git a/src/Locker.php b/src/Locker.php
index 3a4678a..3d59473 100644
--- a/src/Locker.php
+++ b/src/Locker.php
@@ -9,58 +9,36 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine;
-use Hyperf\Coroutine\Traits\Container;
-use Hyperf\Engine\Constant;
-use Hyperf\Engine\Coroutine as Co;
-use Swoole\Coroutine as SwooleCoroutine;
+use Hyperf\Engine\Channel;
class Locker
{
- use Container;
-
- public static function add(string $key, int $id): void
- {
- self::$container[$key][] = $id;
- }
-
- public static function clear(string $key): void
- {
- unset(self::$container[$key]);
- }
+ /**
+ * @var Channel[]
+ */
+ protected static array $channels = [];
public static function lock(string $key): bool
{
- if (! self::has($key)) {
- self::add($key, 0);
+ if (! isset(static::$channels[$key])) {
+ static::$channels[$key] = new Channel(1);
return true;
}
- self::add($key, Coroutine::id());
- // TODO: When the verion of `hyperf/engine` >= 2.0, use `Co::yield()` instead.
- match (Constant::ENGINE) {
- 'Swoole' => SwooleCoroutine::yield(),
- /* @phpstan-ignore-next-line */
- default => Co::yield(),
- };
+
+ $channel = static::$channels[$key];
+ $channel->pop(-1);
return false;
}
public static function unlock(string $key): void
{
- if (self::has($key)) {
- $ids = self::get($key);
- foreach ($ids as $id) {
- if ($id > 0) {
- // TODO: When the verion of `hyperf/engine` >= 2.0, use `Co::resumeById()` instead.
- match (Constant::ENGINE) {
- 'Swoole' => SwooleCoroutine::resume($id),
- /* @phpstan-ignore-next-line */
- default => Co::resumeById($id),
- };
- }
- }
- self::clear($key);
+ if (isset(static::$channels[$key])) {
+ $channel = static::$channels[$key];
+ static::$channels[$key] = null;
+ $channel->close();
}
}
}
diff --git a/src/Mutex.php b/src/Mutex.php
new file mode 100644
index 0000000..ed2d3b5
--- /dev/null
+++ b/src/Mutex.php
@@ -0,0 +1,61 @@
+push(1, $timeout);
+ if ($channel->isTimeout() || $channel->isClosing()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static function unlock(string $key, float $timeout = 5): bool
+ {
+ if (isset(static::$channels[$key])) {
+ $channel = static::$channels[$key];
+ $channel->pop($timeout);
+ if ($channel->isTimeout()) {
+ // unlock more than once
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static function clear(string $key): void
+ {
+ if (isset(static::$channels[$key])) {
+ $channel = static::$channels[$key];
+ static::$channels[$key] = null;
+ $channel->close();
+ }
+ }
+}
diff --git a/src/Parallel.php b/src/Parallel.php
index 22d4083..14f464a 100644
--- a/src/Parallel.php
+++ b/src/Parallel.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine;
use Hyperf\Coroutine\Exception\ParallelExecutionException;
diff --git a/src/Traits/Container.php b/src/Traits/Container.php
deleted file mode 100644
index a1be284..0000000
--- a/src/Traits/Container.php
+++ /dev/null
@@ -1,64 +0,0 @@
-wg = new WaitGroup();
+ }
+
+ public function create(callable $callable): void
+ {
+ $this->wg->add();
+
+ $callable = function () use ($callable) {
+ try {
+ $callable();
+ } finally {
+ $this->wg->done();
+ }
+ };
+
+ parent::create($callable);
+ }
+
+ public function wait(float $timeout = -1): bool
+ {
+ return $this->wg->wait($timeout);
+ }
+}
diff --git a/src/WaitGroup.php b/src/WaitGroup.php
index 67837d9..fa1fa0c 100644
--- a/src/WaitGroup.php
+++ b/src/WaitGroup.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine;
use BadMethodCallException;
diff --git a/src/Waiter.php b/src/Waiter.php
index 7d41ed0..c0231d5 100644
--- a/src/Waiter.php
+++ b/src/Waiter.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace Hyperf\Coroutine;
use Closure;
@@ -29,7 +30,11 @@ public function __construct(float $timeout = 10.0)
}
/**
+ * @template TReturn
+ *
+ * @param Closure():TReturn $closure
* @param null|float $timeout seconds
+ * @return TReturn
*/
public function wait(Closure $closure, ?float $timeout = null)
{
diff --git a/tests/BarrierTest.php b/tests/BarrierTest.php
new file mode 100644
index 0000000..e78248d
--- /dev/null
+++ b/tests/BarrierTest.php
@@ -0,0 +1,40 @@
+assertSame($N, $count);
+ }
+}
diff --git a/tests/Channel/CallerTest.php b/tests/Channel/CallerTest.php
index 9c0f62a..9a480ac 100644
--- a/tests/Channel/CallerTest.php
+++ b/tests/Channel/CallerTest.php
@@ -9,10 +9,12 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine\Channel;
use Hyperf\Coroutine\Channel\Caller;
use Hyperf\Coroutine\Exception\WaitTimeoutException;
+use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use stdClass;
@@ -22,6 +24,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class CallerTest extends TestCase
{
public function testCallerWithNull()
diff --git a/tests/Channel/ChannelManagerTest.php b/tests/Channel/ChannelManagerTest.php
index 3c04882..19c830f 100644
--- a/tests/Channel/ChannelManagerTest.php
+++ b/tests/Channel/ChannelManagerTest.php
@@ -9,10 +9,12 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine\Channel;
use Hyperf\Coroutine\Channel\Manager as ChannelManager;
use Hyperf\Engine\Channel;
+use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use function Hyperf\Coroutine\go;
@@ -21,6 +23,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class ChannelManagerTest extends TestCase
{
public function testChannelManager()
diff --git a/tests/ConcurrentTest.php b/tests/ConcurrentTest.php
index 6363152..9b5168b 100644
--- a/tests/ConcurrentTest.php
+++ b/tests/ConcurrentTest.php
@@ -9,12 +9,14 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine;
use Exception;
use Hyperf\Context\ApplicationContext;
use Hyperf\Coroutine\Concurrent;
use Mockery;
+use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Swoole\Coroutine;
@@ -23,6 +25,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class ConcurrentTest extends TestCase
{
protected function setUp(): void
diff --git a/tests/ContainerTest.php b/tests/ContainerTest.php
new file mode 100644
index 0000000..6943fcf
--- /dev/null
+++ b/tests/ContainerTest.php
@@ -0,0 +1,32 @@
+assertSame($id, Foo::get('test'));
+ $this->assertFalse(Bar::has('test'));
+ $this->assertEmpty(Bar::list());
+ }
+}
diff --git a/tests/CoroutineTest.php b/tests/CoroutineTest.php
index 947b1e9..a8c67dc 100644
--- a/tests/CoroutineTest.php
+++ b/tests/CoroutineTest.php
@@ -9,6 +9,7 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine;
use Exception;
@@ -19,6 +20,8 @@
use Hyperf\Engine\Exception\CoroutineDestroyedException;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
use Mockery;
+use PHPUnit\Framework\Attributes\CoversNothing;
+use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Throwable;
@@ -31,6 +34,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class CoroutineTest extends TestCase
{
protected function tearDown(): void
@@ -68,9 +72,7 @@ public function testCoroutineParentIdHasBeenDestroyed()
}
}
- /**
- * @group NonCoroutine
- */
+ #[Group('NonCoroutine')]
public function testCoroutineInTopCoroutine()
{
run(function () {
diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php
index 7d3b40b..b1dcc6c 100644
--- a/tests/FunctionTest.php
+++ b/tests/FunctionTest.php
@@ -9,10 +9,13 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Engine\Channel;
+use PHPUnit\Framework\Attributes\CoversNothing;
+use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use Swoole\Runtime;
@@ -25,6 +28,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class FunctionTest extends TestCase
{
public function testReturnOfGo()
@@ -38,9 +42,7 @@ public function testReturnOfGo()
$this->assertSame('Hyperf', $uniqid);
}
- /**
- * @group NonCoroutine
- */
+ #[Group('NonCoroutine')]
public function testRun()
{
$asserts = [
diff --git a/tests/LockerTest.php b/tests/LockerTest.php
index c3c2fe0..91fc2a8 100644
--- a/tests/LockerTest.php
+++ b/tests/LockerTest.php
@@ -9,10 +9,12 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine;
use Hyperf\Coroutine\Locker;
use Hyperf\Engine\Channel;
+use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use function Hyperf\Coroutine\go;
@@ -21,6 +23,7 @@
* @internal
* @coversNothing
*/
+#[CoversNothing]
class LockerTest extends TestCase
{
public function testLockAndUnlock()
diff --git a/tests/MutexTest.php b/tests/MutexTest.php
new file mode 100644
index 0000000..679e458
--- /dev/null
+++ b/tests/MutexTest.php
@@ -0,0 +1,60 @@
+push($value);
+ } finally {
+ Mutex::unlock('test');
+ }
+ }
+ };
+
+ $wg = new WaitGroup(5);
+ foreach (['h', 'e', 'l', 'l', 'o'] as $value) {
+ go(function () use ($func, $value, $wg) {
+ $func($value);
+ $wg->done();
+ });
+ }
+
+ $res = '';
+ $wg->wait(1);
+ for ($i = 0; $i < 5; ++$i) {
+ $res .= $chan->pop(1);
+ }
+
+ $this->assertSame('hello', $res);
+ }
+}
diff --git a/tests/ParallelTest.php b/tests/ParallelTest.php
index 29f9983..00d7475 100644
--- a/tests/ParallelTest.php
+++ b/tests/ParallelTest.php
@@ -9,12 +9,14 @@
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
+
namespace HyperfTest\Coroutine;
use Exception;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Coroutine\Exception\ParallelExecutionException;
use Hyperf\Coroutine\Parallel;
+use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use Throwable;
@@ -23,8 +25,9 @@
/**
* @internal
- * @covers \Hyperf\Coroutine\Parallel
+ * @coversNothing
*/
+#[CoversClass(Parallel::class)]
class ParallelTest extends TestCase
{
public function testParallel()
diff --git a/tests/Stub/Bar.php b/tests/Stub/Bar.php
new file mode 100644
index 0000000..e59fae5
--- /dev/null
+++ b/tests/Stub/Bar.php
@@ -0,0 +1,20 @@
+