Skip to content
New issue

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

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

Already on GitHub? Sign in 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.

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

No branches or pull requests

1 participant