Fibers
Revolt is designed to work well with fibers. All event callbacks are run in a separate fiber and can suspend it at any time. If there are no suspensions in an event callback, the fiber will be reused for future event callbacks to save resources.
Suspensions
Suspensions allow awaiting an event by suspending the current execution context until the event in question happened.
They will suspend the current fiber and return to the event loop, or start running the event loop if called from outside a fiber, i.e. from {main}
.
Fibers should be suspended and resumed using the Revolt\EventLoop\Suspension
API.
Suspension
objects can be created using Revolt\EventLoop::getSuspension()
.
After obtaining a Suspension
object, an event callback can be registered to schedule the resumption of the current fiber.
$suspension->suspend()
will suspend the current execution context until it is resumed via $suspension->resume()
or $suspension->throw()
.
Example
Let’s suspend the main execution context until there’s data to read from STDIN
or a timeout expires:
<?php
require __DIR__ . '/vendor/autoload.php';
use Revolt\EventLoop;
if (\stream_set_blocking(STDIN, false) !== true) {
\fwrite(STDERR, "Unable to set STDIN to non-blocking" . PHP_EOL);
exit(1);
}
print "Write something and hit enter" . PHP_EOL;
$suspension = EventLoop::getSuspension();
$readableId = EventLoop::onReadable(STDIN, function ($id, $stream) use ($suspension): void {
EventLoop::cancel($id);
$chunk = \fread($stream, 8192);
print "Read " . \strlen($chunk) . " bytes" . PHP_EOL;
$suspension->resume(null);
});
$timeoutId = EventLoop::delay(5, function () use ($readableId, $suspension) {
EventLoop::cancel($readableId);
print "Timeout reached" . PHP_EOL;
$suspension->resume(null);
});
$suspension->suspend();
EventLoop::cancel($readableId);
EventLoop::cancel($timeoutId);