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

Fatal error: Uncaught AssertionError: assert($fiber !== $this->fiber) when server::stop() in Windows sapi_windows_set_ctrl_handler() #29

Open
DrLightman opened this issue Jan 5, 2025 · 3 comments

Comments

@DrLightman
Copy link

I adapted the last lines of the example in the README to Windows, because SIGINT (pcntl) is not available there.
I converted it this way making use of sapi_windows_set_ctrl_handler($callback) to intercept CTRL+C whilst the script is running in a terminal.

EventLoop::defer( function () use ( $logger, $server ): void {
    $logger->info( 'OS: Windows' );
    // async wait for server admin to hit CTRL+C
    sapi_windows_set_ctrl_handler( function ( int $event ) use ( $logger, $server ) {
        $logger->info( sprintf( "Received signal, stopping HTTP server" ) );
        $server->stop();
    } );
} );

EventLoop::run();

The callback is fired, the server says is stopping, but an assertion fires afterward, I don't think it successfully stops:

...
...
[2025-01-05T14:39:38.870938+00:00] server.info: OS: Windows
[2025-01-05T14:39:41.882420+00:00] server.info: Received signal, stopping HTTP server
[2025-01-05T14:39:41.882738+00:00] server.info: Stopping server

Fatal error: Uncaught AssertionError: assert($fiber !== $this->fiber) in D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php:293
Stack trace:
#0 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php(293): assert(false, 'assert($fiber !...')
#1 D:\server-php\vendor\revolt\event-loop\src\EventLoop.php(392): Revolt\EventLoop\Internal\AbstractDriver->getSuspension()
#2 D:\server-php\vendor\amphp\amp\src\Internal\FutureIterator.php(130): Revolt\EventLoop::getSuspension()
#3 D:\server-php\vendor\amphp\amp\src\Future.php(59): Amp\Internal\FutureIterator->consume()
#4 D:\server-php\vendor\amphp\amp\src\Future\functions.php(118): Amp\Future::iterate(Array, NULL)
#5 D:\server-php\vendor\amphp\http-server\src\SocketHttpServer.php(402): Amp\Future\awaitAll(Array)
#6 D:\server-php\start-php8.php(88): Amp\Http\Server\SocketHttpServer->stop()
#7 [internal function]: {closure:D:\server-php\start-php8.php:85}(0)
#8 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Driver\StreamSelectDriver.php(254): stream_select(Array, Array, Array, 0, 999642)
#9 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Driver\StreamSelectDriver.php(133): Revolt\EventLoop\Driver\StreamSelectDriver->selectStreams(Array, Array, 0.9996424000019)
#10 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php(489): Revolt\EventLoop\Driver\StreamSelectDriver->dispatch(true)
#11 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php(552): Revolt\EventLoop\Internal\AbstractDriver->tick(true)
#12 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():533}()
#13 D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php(113): Fiber->resume()
#14 D:\server-php\vendor\revolt\event-loop\src\EventLoop.php(406): Revolt\EventLoop\Internal\AbstractDriver->run()
#15 D:\server-php\start-php8.php(106): Revolt\EventLoop::run()
#16 {main}
  thrown in D:\server-php\vendor\revolt\event-loop\src\EventLoop\Internal\AbstractDriver.php on line 293

This is not breaking the script atm but maybe it's worth taking a look into it?

@bwoebi
Copy link
Member

bwoebi commented Jan 5, 2025

The problem is that sapi_windows_set_ctrl_handler works via the internal interrupt mechanism and will cause execution of its closure within the event loop fiber itself (where fiber switches are not allowed).

I haven't tested it, but wrapping the contents of the closure inside EventLoop::queue (microtask) may work, i.e.:

    sapi_windows_set_ctrl_handler( function ( int $event ) use ( $logger, $server ) {
        EventLoop::queue(function() use ($looger, $server) {
            $logger->info( sprintf( "Received signal, stopping HTTP server" ) );
            $server->stop();
        });
    } );

@bwoebi
Copy link
Member

bwoebi commented Jan 5, 2025

But absent manual handling to defer, it would probably require support in Revolt itself, as part of the event loop.

@DrLightman
Copy link
Author

Thank you for the ideas, I tried I think almost all combinations of closures/scopes but the error persists, maybe it hasn't solution with the actual state of the library, maybe I'll drop an issue in the github of Revolt.

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

2 participants