Skip to content

Commit b7db7ca

Browse files
authored
Guard against garbage collection invoking close() on an already destructed file
Unfortunately this has to live inside the async() block as microtasks race depending on the order of execution of destructors.
1 parent 3c57ba9 commit b7db7ca

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

src/Driver/ParallelFile.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public function __destruct()
6464
{
6565
if ($this->id !== null && $this->worker->isRunning()) {
6666
$id = $this->id;
67+
$this->id = null;
6768
$worker = $this->worker;
6869
EventLoop::queue(static fn () => $worker->execute(new Internal\FileTask('fclose', [], $id)));
6970
}
@@ -88,14 +89,19 @@ public function close(): void
8889

8990
$this->closing = async(function (): void {
9091
$id = $this->id;
91-
$this->id = null;
92-
$this->worker->execute(new Internal\FileTask('fclose', [], $id));
92+
// Guard against explicit close calls happening inside garbage collection
93+
if ($id !== null) {
94+
$this->id = null;
95+
$this->worker->execute(new Internal\FileTask('fclose', [], $id));
96+
}
9397
});
9498

9599
try {
96100
$this->closing->await();
97101
} finally {
98-
$this->onClose->complete();
102+
if (!$this->onClose->isComplete()) {
103+
$this->onClose->complete();
104+
}
99105
$this->lockType = null;
100106
}
101107
}

0 commit comments

Comments
 (0)