Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Resumptions in final cycle collection after EventLoop return in DriverSuspension are ignored #90

Open
bwoebi opened this issue Dec 23, 2023 · 0 comments

Comments

@bwoebi
Copy link
Contributor

bwoebi commented Dec 23, 2023

Consider these test cases (the one case immediately resumes in cycle collection, the other schedules something on the event loop):

    public function testSuspensionResumptionWithQueueInGarbageCollection(): void
    {
        $suspension = EventLoop::getSuspension();

        $class = new class($suspension) {
            public function __construct(public Suspension $suspension) {}
            public function __destruct() { $this->suspension->resume(true); }
        };
        $cycle = [$class, &$cycle];
        unset($class, $cycle);

        $ended = $suspension->suspend();

        $this->assertTrue($ended);
    }

    public function testEventLoopResumptionWithQueueInGarbageCollection(): void
    {
        $suspension = EventLoop::getSuspension();

        $class = new class($suspension) {
            public function __construct(public Suspension $suspension) {}
            public function __destruct() { EventLoop::queue($this->suspension->resume(...), true); }
        };
        $cycle = [$class, &$cycle];
        unset($class, $cycle);

        $ended = $suspension->suspend();

        $this->assertTrue($ended);
    }

These cases both will fail with:

Error: Event loop terminated without resuming the current suspension (the cause is either a fiber deadlock, or an incorrectly unreferenced/canceled watcher):

(The trailing colon is also weird, it means that no other fibers exist, maybe write that out.)

I was initially very confused when this happened in my code as dumping the event loop showed a pending queue() call, while the EventLoop reported as finished.

I would expect that, after the gc_collect_cycles():

\gc_collect_cycles(); // Collect any circular references before dumping pending suspensions.

the EventLoop is checked for any active, referenced watchers or microtasks, and if yes, is resumed. Similarly, if a suspension was resumed within that cycle collection, it will leave the code path leading to the error being thrown.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

1 participant