Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions src/EventLoop.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Revolt;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\DriverFactory;
use Revolt\EventLoop\Internal\AbstractDriver;
Expand Down Expand Up @@ -317,29 +318,49 @@ public static function getErrorHandler(): ?\Closure
}

/**
* Retrieve an associative array of information about the event loop driver.
* Returns all registered non-cancelled callback identifiers.
*
* The returned array MUST contain the following data describing the driver's currently registered callbacks:
* @return string[] Callback identifiers.
*/
public static function getIdentifiers(): array
{
return self::getDriver()->getIdentifiers();
}

/**
* Returns the type of the callback identified by the given callback identifier.
*
* [
* "defer" => ["enabled" => int, "disabled" => int],
* "delay" => ["enabled" => int, "disabled" => int],
* "repeat" => ["enabled" => int, "disabled" => int],
* "on_readable" => ["enabled" => int, "disabled" => int],
* "on_writable" => ["enabled" => int, "disabled" => int],
* "on_signal" => ["enabled" => int, "disabled" => int],
* "enabled_watchers" => ["referenced" => int, "unreferenced" => int],
* "running" => bool
* ];
* @param string $callbackId The callback identifier.
*
* Implementations MAY optionally add more information in the array but at minimum the above `key => value` format
* MUST always be provided.
* @return CallbackType The callback type.
*/
public static function getType(string $callbackId): CallbackType
{
return self::getDriver()->getType($callbackId);
}

/**
* Returns whether the callback identified by the given callback identifier is currently enabled.
*
* @param string $callbackId The callback identifier.
*
* @return bool {@code true} if the callback is currently enabled, otherwise {@code false}.
*/
public static function isEnabled(string $callbackId): bool
{
return self::getDriver()->isEnabled($callbackId);
}

/**
* Returns whether the callback identified by the given callback identifier is currently referenced.
*
* @param string $callbackId The callback identifier.
*
* @return array Statistics about the loop in the described format.
* @return bool {@code true} if the callback is currently referenced, otherwise {@code false}.
*/
public static function getInfo(): array
public static function isReferenced(string $callbackId): bool
{
return self::getDriver()->getInfo();
return self::getDriver()->isReferenced($callbackId);
}

/**
Expand Down
13 changes: 13 additions & 0 deletions src/EventLoop/CallbackType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Revolt\EventLoop;

enum CallbackType
{
case Defer;
case Delay;
case Repeat;
case Readable;
case Writable;
case Signal;
}
50 changes: 32 additions & 18 deletions src/EventLoop/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,31 +272,45 @@ public function getErrorHandler(): ?\Closure;
public function getHandle(): mixed;

/**
* Returns the same array of data as getInfo().
* Returns all registered non-cancelled callback identifiers.
*
* @return array
* @return string[] Callback identifiers.
*/
public function __debugInfo(): array;
public function getIdentifiers(): array;

/**
* Returns the type of the callback identified by the given callback identifier.
*
* @param string $callbackId The callback identifier.
*
* @return CallbackType The callback type.
*/
public function getType(string $callbackId): CallbackType;

/**
* Returns whether the callback identified by the given callback identifier is currently enabled.
*
* @param string $callbackId The callback identifier.
*
* @return bool {@code true} if the callback is currently enabled, otherwise {@code false}.
*/
public function isEnabled(string $callbackId): bool;

/**
* Retrieve an associative array of information about the event loop driver.
* Returns whether the callback identified by the given callback identifier is currently referenced.
*
* The returned array MUST contain the following data describing the driver's currently registered callbacks:
* @param string $callbackId The callback identifier.
*
* [
* "defer" => ["enabled" => int, "disabled" => int],
* "delay" => ["enabled" => int, "disabled" => int],
* "repeat" => ["enabled" => int, "disabled" => int],
* "on_readable" => ["enabled" => int, "disabled" => int],
* "on_writable" => ["enabled" => int, "disabled" => int],
* "on_signal" => ["enabled" => int, "disabled" => int],
* "enabled_watchers" => ["referenced" => int, "unreferenced" => int],
* ];
* @return bool {@code true} if the callback is currently referenced, otherwise {@code false}.
*/
public function isReferenced(string $callbackId): bool;

/**
* Returns some useful information about the event loop.
*
* Implementations MAY optionally add more information in the array but at minimum the above `key => value` format
* MUST always be provided.
* If this method isn't implemented, dumping the event loop in a busy application, even indirectly, is a pain.
*
* @return array Statistics about the loop in the described format.
* @return array
*/
public function getInfo(): array;
public function __debugInfo(): array;
}
20 changes: 18 additions & 2 deletions src/EventLoop/Driver/TracingDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\InvalidCallbackError;
use Revolt\EventLoop\Suspension;
Expand Down Expand Up @@ -203,9 +204,24 @@ public function dump(): string
return \rtrim($dump);
}

public function getInfo(): array
public function getIdentifiers(): array
{
return $this->driver->getInfo();
return $this->driver->getIdentifiers();
}

public function getType(string $callbackId): CallbackType
{
return $this->driver->getType($callbackId);
}

public function isEnabled(string $callbackId): bool
{
return $this->driver->isEnabled($callbackId);
}

public function isReferenced(string $callbackId): bool
{
return $this->driver->isReferenced($callbackId);
}

public function __debugInfo(): array
Expand Down
80 changes: 30 additions & 50 deletions src/EventLoop/Internal/AbstractDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Revolt\EventLoop\Internal;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\FiberLocal;
use Revolt\EventLoop\InvalidCallbackError;
Expand Down Expand Up @@ -303,65 +304,44 @@ public function getErrorHandler(): ?\Closure
public function __debugInfo(): array
{
// @codeCoverageIgnoreStart
return $this->getInfo();
return \array_map(fn (DriverCallback $callback) => [
'type' => $this->getType($callback->id),
'enabled' => $callback->enabled,
'referenced' => $callback->referenced,
], $this->callbacks);
// @codeCoverageIgnoreEnd
}

public function getInfo(): array
public function getIdentifiers(): array
{
$counts = [
"referenced" => 0,
"unreferenced" => 0,
];
return \array_keys($this->callbacks);
}

$defer = $delay = $repeat = $onReadable = $onWritable = $onSignal = [
"enabled" => 0,
"disabled" => 0,
];
public function getType(string $callbackId): CallbackType
{
$callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

foreach ($this->callbacks as $callback) {
if ($callback instanceof StreamReadableCallback) {
$array = &$onReadable;
} elseif ($callback instanceof StreamWritableCallback) {
$array = &$onWritable;
} elseif ($callback instanceof SignalCallback) {
$array = &$onSignal;
} elseif ($callback instanceof TimerCallback) {
if ($callback->repeat) {
$array = &$repeat;
} else {
$array = &$delay;
}
} elseif ($callback instanceof DeferCallback) {
$array = &$defer;
} else {
// @codeCoverageIgnoreStart
throw new \Error("Unknown callback type");
// @codeCoverageIgnoreEnd
}
return match ($callback::class) {
DeferCallback::class => CallbackType::Defer,
TimerCallback::class => $callback->repeat ? CallbackType::Repeat : CallbackType::Delay,
StreamReadableCallback::class => CallbackType::Readable,
StreamWritableCallback::class => CallbackType::Writable,
SignalCallback::class => CallbackType::Signal,
};
}

if ($callback->enabled) {
++$array["enabled"];
public function isEnabled(string $callbackId): bool
{
$callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

if ($callback->referenced) {
++$counts["referenced"];
} else {
++$counts["unreferenced"];
}
} else {
++$array["disabled"];
}
}
return $callback->enabled;
}

public function isReferenced(string $callbackId): bool
{
$callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

return [
"enabled_watchers" => $counts,
"defer" => $defer,
"delay" => $delay,
"repeat" => $repeat,
"on_readable" => $onReadable,
"on_writable" => $onWritable,
"on_signal" => $onSignal,
];
return $callback->referenced;
}

/**
Expand Down
Loading