Skip to content

Commit 0ffcb50

Browse files
committed
fix: scheduler::resume/throw behavior adds a pre check before execution.
1 parent 8d600a3 commit 0ffcb50

5 files changed

Lines changed: 25 additions & 35 deletions

File tree

src/Runtime/FiberCoroutine.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ final class FiberCoroutine extends Coroutine
3434
*/
3535
public function __get(string $name): mixed
3636
{
37-
return match($name) {
37+
return match ($name) {
3838
'result' => $this->result,
39-
default => new UnexpectedValueException("Property {$name} does not exist or is not accessible")
39+
default => new UnexpectedValueException("Property {$name} does not exist or is not accessible")
4040
};
4141
}
4242

@@ -74,7 +74,6 @@ public function start(): mixed
7474
try {
7575
$result = $this->fiber->start(...$this->args);
7676
} catch (Throwable $exception) {
77-
$this->result = $exception;
7877
$this->setState(Coroutine::STATE_DEAD);
7978
throw $exception;
8079
}
@@ -103,15 +102,9 @@ public function suspend(mixed $value = null): mixed
103102
}
104103

105104
$this->setState(Coroutine::STATE_WAITING);
106-
107-
try {
108-
$result = $this->fiber->suspend($value);
109-
} catch (Throwable $exception) {
110-
$this->setState(Coroutine::STATE_DEAD);
111-
throw $exception;
112-
}
113-
105+
$result = $this->fiber->suspend($value);
114106
$this->setState(Coroutine::STATE_RUNNING);
107+
115108
return $result;
116109
}
117110

@@ -123,6 +116,10 @@ public function suspend(mixed $value = null): mixed
123116
*/
124117
public function resume(mixed $value = null): mixed
125118
{
119+
if ($this->state !== Coroutine::STATE_WAITING) {
120+
throw new CoroutineStateException('Coroutine::resume() called with coroutine not in running state');
121+
}
122+
126123
$this->setState(Coroutine::STATE_RUNNING);
127124

128125
try {
@@ -151,6 +148,10 @@ public function resume(mixed $value = null): mixed
151148
*/
152149
public function throw(Throwable $exception): mixed
153150
{
151+
if ($this->state !== Coroutine::STATE_WAITING) {
152+
throw new CoroutineStateException('Coroutine::throw() called with coroutine not in running state');
153+
}
154+
154155
$this->setState(Coroutine::STATE_RUNNING);
155156

156157
try {
@@ -182,7 +183,7 @@ public function recycle(?Closure $callback = null): void
182183
new CoroutineStateException("Unable to recycle a coroutine in use");
183184
}
184185

185-
$this->fiber = new Fiber($callback);
186+
$this->callback = $callback;
186187
$this->recycleReset();
187188
}
188189

src/Runtime/Scheduler.php

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929

3030
use function array_shift;
3131
use function str_repeat;
32-
use function array_slice;
33-
use function debug_backtrace;
3432

3533
Runtime::init();
3634

@@ -140,7 +138,7 @@ public static function enqueue(Coroutine $coroutine, bool $immediate = false): v
140138
$coroutine->state(),
141139
Coroutine::STATE_RUNNABLE,
142140
$coroutine,
143-
"self::enqueue() called with non-runnable coroutine"
141+
"Scheduler::enqueue() called with non-runnable coroutine"
144142
);
145143
}
146144

@@ -281,8 +279,6 @@ public static function runnableQueue(): SplQueue
281279
*/
282280
public static function start(Coroutine $coroutine): void
283281
{
284-
Runtime::$DEBUG &&
285-
$coroutine->addTrace($coroutine->state(), 'start', array_slice(debug_backtrace(), 0, 1));
286282
$coroutine->runnable();
287283

288284
self::$coroutineMap[$coroutine->key()] = WeakReference::create($coroutine);
@@ -307,9 +303,6 @@ public static function start(Coroutine $coroutine): void
307303
*/
308304
public static function resume(Coroutine $coroutine, mixed $value = null): ControlResult
309305
{
310-
Runtime::$DEBUG &&
311-
$coroutine->addTrace($coroutine->state(), 'resume', array_slice(debug_backtrace(), 0, 1));
312-
313306
try {
314307
return new ControlResult('resume', $coroutine->resume($value), $coroutine);
315308
} catch (Throwable $exception) {
@@ -330,9 +323,6 @@ public static function resume(Coroutine $coroutine, mixed $value = null): Contro
330323
*/
331324
public static function throw(Coroutine $coroutine, Throwable $exception): ControlResult
332325
{
333-
Runtime::$DEBUG &&
334-
$coroutine->addTrace($coroutine->state(), 'throw', array_slice(debug_backtrace(), 0, 1));
335-
336326
try {
337327
return new ControlResult('throw', $coroutine->throw($exception), $coroutine);
338328
} catch (Throwable $exception) {

src/Runtime/Trait/StateMachine.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
use Closure;
1616
use Ripple\Coroutine;
17+
use Ripple\Runtime\Exception\CoroutineException;
1718

1819
use function array_pop;
1920
use function array_reverse;
@@ -64,6 +65,12 @@ public function setState(string $state): void
6465
return;
6566
}
6667

68+
if ($state === Coroutine::STATE_DEAD && isset($this->fiber)) {
69+
if (!$this->fiber->isTerminated()) {
70+
throw new CoroutineException('状态不同步');
71+
}
72+
}
73+
6774
$this->state = $state;
6875

6976
// 内部分发

tests/Net/HttpFileTransferTest.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,6 @@ public function testFileDownload(): void
168168

169169
$serverMd5 = $response->getHeaderLine('Content-MD5');
170170
$localMd5 = md5_file($downloadedFile);
171-
$serverContentLength = $response->getHeaderLine('Content-Length');
172-
$localFileSize = filesize($downloadedFile);
173-
174-
echo "serverMd5: $serverMd5\n";
175-
echo "localMd5: $localMd5\n";
176-
echo "serverContentLength: $serverContentLength\n";
177-
echo "localFileSize: $localFileSize\n";
178-
179171
$this->assertNotEmpty($serverMd5, '服务器未返回Content-MD5头');
180172
$this->assertEquals($serverMd5, $localMd5, '下载文件MD5校验失败');
181173

tests/Sync/MutexTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function testMultipleCoroutinesCompeting(): void
9090
go(function () use ($mutex, &$sharedData, &$results, $i) {
9191
$mutex->lock();
9292

93-
Time::sleep(1);
93+
Time::sleep(0.1);
9494
$oldValue = $sharedData;
9595
$sharedData = $oldValue + 1;
9696
$results[] = "Coroutine $i: $oldValue -> $sharedData";
@@ -152,12 +152,12 @@ public function testUnlockByNonOwner(): void
152152
go(function () use ($mutex, &$results) {
153153
$mutex->lock();
154154
$results[] = "Coroutine 1 got lock";
155-
Time::sleep(1);
155+
Time::sleep(0.1);
156156
});
157157

158158
// 协程2尝试解锁协程1的锁
159159
go(function () use ($mutex, &$results) {
160-
Time::sleep(1);
160+
Time::sleep(0.1);
161161
try {
162162
$mutex->unlock();
163163
$results[] = "Coroutine 2 unlocked (should not happen)";
@@ -262,7 +262,7 @@ public function testConcurrentLockSafety(): void
262262
$coroutines[] = go(function () use ($mutex, &$counter, &$results, $i) {
263263
for ($j = 0; $j < 10; $j++) {
264264
$mutex->lock();
265-
Time::sleep(1); // 模拟一些工作
265+
Time::sleep(0.1); // 模拟一些工作
266266
$counter++;
267267
$mutex->unlock();
268268
}

0 commit comments

Comments
 (0)