From b3fdfa4edeefc0173d02d6ae468f5899bcb52829 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 25 Aug 2016 22:48:21 +0200 Subject: [PATCH 01/30] Fixed #90 - allow disabling of invalid watchers --- src/Loop.php | 2 -- src/Loop/Driver.php | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 9e7e7b6..fe9cc55 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -237,8 +237,6 @@ public static function enable($watcherId) * @param string $watcherId The watcher identifier. * * @return void - * - * @throws InvalidWatcherException If the watcher identifier is invalid. */ public static function disable($watcherId) { diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index d2f70f8..19b1f88 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -134,19 +134,18 @@ abstract public function onSignal($signo, callable $callback, $data = null); abstract public function enable($watcherId); /** - * Disable a watcher. Disabling a watcher MUST NOT invalidate the watcher. + * Disable a watcher. Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, + * even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * * @return void - * - * @throws InvalidWatcherException If the watcher identifier is invalid. */ abstract public function disable($watcherId); /** * Cancel a watcher. This will detatch the event loop from all resources that are associated to the watcher. After - * this operation the watcher is permanently invalid. Calling this function MUST never fail, even when passed an + * this operation the watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an * invalid watcher. * * @param string $watcherId The watcher identifier. From 32286779535feaabf0c92624fd8ebb7aa3c0791d Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Wed, 21 Sep 2016 18:05:59 +0200 Subject: [PATCH 02/30] Change exception base classes to Exception Resolves #93. --- src/Loop/InvalidWatcherException.php | 7 ++++--- src/Loop/UnsupportedFeatureException.php | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Loop/InvalidWatcherException.php b/src/Loop/InvalidWatcherException.php index 06360dd..80cdf7d 100644 --- a/src/Loop/InvalidWatcherException.php +++ b/src/Loop/InvalidWatcherException.php @@ -3,10 +3,11 @@ namespace Interop\Async\Loop; /** - * MUST be thrown if any operation (except cancel()) is attempted with an invalid watcher identifier. An invalid watcher - * identifier is any identifier that is not yet emitted by the driver or cancelled by the user. + * MUST be thrown if any operation (except disable() and cancel()) is attempted with an invalid watcher identifier. + * + * An invalid watcher identifier is any identifier that is not yet emitted by the driver or cancelled by the user. */ -class InvalidWatcherException extends \LogicException +class InvalidWatcherException extends \Exception { } diff --git a/src/Loop/UnsupportedFeatureException.php b/src/Loop/UnsupportedFeatureException.php index 03c8c9c..bfc93c7 100644 --- a/src/Loop/UnsupportedFeatureException.php +++ b/src/Loop/UnsupportedFeatureException.php @@ -3,11 +3,11 @@ namespace Interop\Async\Loop; /** - * Must be thrown if a feature is not supported by the system. + * MUST be thrown if a feature is not supported by the system. * - * This might happen if PCNTL is missing and the loop driver doesn't support another way to dispatch signals. + * This might happen if ext-pcntl is missing and the loop driver doesn't support another way to dispatch signals. */ -class UnsupportedFeatureException extends \RuntimeException +class UnsupportedFeatureException extends \Exception { } From 3791a7536a5b2f09418a0e13d0d3570c3a7d20d1 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 4 Sep 2016 22:45:37 +0200 Subject: [PATCH 03/30] Add missing documentation --- src/Loop.php | 5 +++++ src/Loop/Driver.php | 37 ++++++++++++++++++++----------------- src/Loop/DriverFactory.php | 5 +++++ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index fe9cc55..e92a719 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -7,6 +7,11 @@ use Interop\Async\Loop\InvalidWatcherException; use Interop\Async\Loop\UnsupportedFeatureException; +/** + * Accessor to allow global access to the event loop. + * + * @see \Interop\Async\Loop\Driver + */ final class Loop { /** diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 19b1f88..fd2ac07 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -2,6 +2,9 @@ namespace Interop\Async\Loop; +/** + * Event loop driver which implements all basic operations to allow interoperability. + */ abstract class Driver { /** @@ -106,8 +109,8 @@ abstract public function onWritable($stream, callable $callback, $data = null); * Multiple watchers on the same signal may be executed in any order. * * NOTE: Installing a same signal on different instances of this interface is deemed undefined behavior. - * Implementations may try to detect this, if possible, but are not required to. - * This is due to technical limitations of the signals being registered globally per process. + * Implementations may try to detect this, if possible, but are not required to. This is due to technical + * limitations of the signals being registered globally per process. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. @@ -188,8 +191,8 @@ abstract public function unreference($watcherId); * * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` * - * @param string $key namespaced storage key - * @param mixed $value the value to be stored + * @param string $key The namespaced storage key. + * @param mixed $value The value to be stored. * * @return void */ @@ -208,9 +211,9 @@ final public function setState($key, $value) * * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` * - * @param string $key namespaced storage key + * @param string $key The namespaced storage key. * - * @return mixed previously stored value or null if it doesn't exist + * @return mixed The previously stored value or null if it doesn't exist. */ final public function getState($key) { @@ -234,15 +237,15 @@ abstract public function setErrorHandler(callable $callback = null); * * The returned array MUST contain the following data describing the driver's currently registered watchers: * - * [ - * "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], - * "watchers" => ["referenced" => int, "unreferenced" => int], - * ]; + * [ + * "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], + * "watchers" => ["referenced" => int, "unreferenced" => int], + * ]; * * Implementations MAY optionally add more information in the array but at minimum the above key => value format * MUST always be provided. @@ -254,9 +257,9 @@ abstract public function info(); /** * Get the underlying loop handle. * - * Example: the uv_loop resource for libuv or the EvLoop object for libev or null for a native driver + * Example: the uv_loop resource for libuv or the EvLoop object for libev or null for a native driver. * - * Note: This function is *not* exposed in the Loop class; users shall access it directly on the respective loop + * NOTE: This function is *not* exposed in the Loop class. Users shall access it directly on the respective loop * instance. * * @return null|object|resource The loop handle the event loop operates on. Null if there is none. diff --git a/src/Loop/DriverFactory.php b/src/Loop/DriverFactory.php index 83ba560..97b4eb9 100644 --- a/src/Loop/DriverFactory.php +++ b/src/Loop/DriverFactory.php @@ -2,6 +2,11 @@ namespace Interop\Async\Loop; +/** + * Allows creating new driver instances. + * + * @see \Interop\Async\Loop::setFactory() + */ interface DriverFactory { /** From 74ff6a4be158377a5e565c3a820611db2f6fe0e8 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 23 Sep 2016 16:02:23 +0200 Subject: [PATCH 04/30] Clarify that (half-)closed streams also trigger the respective read and write watchers --- src/Loop.php | 4 ++-- src/Loop/Driver.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index e92a719..b486d25 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -172,7 +172,7 @@ public static function repeat($interval, callable $callback, $data = null) } /** - * Execute a callback when a stream resource becomes readable. + * Execute a callback when a stream resource becomes readable or is closed for reading. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. @@ -187,7 +187,7 @@ public static function onReadable($stream, callable $callback, $data = null) } /** - * Execute a callback when a stream resource becomes writable. + * Execute a callback when a stream resource becomes writable or is closed for writing. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index fd2ac07..3949adf 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -78,7 +78,7 @@ abstract public function delay($delay, callable $callback, $data = null); abstract public function repeat($interval, callable $callback, $data = null); /** - * Execute a callback when a stream resource becomes readable. + * Execute a callback when a stream resource becomes readable or is closed for reading. * * Multiple watchers on the same stream may be executed in any order. * @@ -91,7 +91,7 @@ abstract public function repeat($interval, callable $callback, $data = null); abstract public function onReadable($stream, callable $callback, $data = null); /** - * Execute a callback when a stream resource becomes writable. + * Execute a callback when a stream resource becomes writable or is closed for writing. * * Multiple watchers on the same stream may be executed in any order. * From 876ca66876d67a2ff53cbabcfc3f681ecff25a01 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sat, 24 Sep 2016 21:51:31 +0200 Subject: [PATCH 05/30] Fix code markdown for Loop::info --- src/Loop.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index b486d25..a8f3fae 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -353,15 +353,15 @@ public static function setErrorHandler(callable $callback = null) * * The returned array MUST contain the following data describing the driver's currently registered watchers: * - * [ - * "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], - * "watchers" => ["referenced" => int, "unreferenced" => int], - * ]; + * [ + * "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], + * "watchers" => ["referenced" => int, "unreferenced" => int], + * ]; * * Implementations MAY optionally add more information in the array but at minimum the above key => value format * MUST always be provided. From 77764d5b8988cc5c1f40d093ed8d6497876288ef Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 25 Sep 2016 13:22:01 +0200 Subject: [PATCH 06/30] Format docs, change LogicException to Exception --- src/Loop.php | 67 +++++++++++++++++++------------------ src/Loop/Driver.php | 80 ++++++++++++++++++++++++--------------------- 2 files changed, 78 insertions(+), 69 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index a8f3fae..fa9593b 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -32,11 +32,11 @@ final class Loop /** * Set the factory to be used to create a default drivers. * - * Setting a factory is only allowed as long as no loop is currently running. Passing null will reset the default - * driver and remove the factory. + * Setting a factory is only allowed as long as no loop is currently running. Passing null will reset the + * default driver and remove the factory. * - * The factory will be invoked if none is passed to Loop::execute. A default driver will be created to support - * synchronous waits in traditional applications. + * The factory will be invoked if none is passed to `Loop::execute`. A default driver will be created to + * support synchronous waits in traditional applications. * * @param DriverFactory|null $factory New factory to replace the previous one. */ @@ -56,9 +56,11 @@ public static function setFactory(DriverFactory $factory = null) * Execute a callback within the scope of an event loop driver. * * @param callable $callback The callback to execute. - * @param Driver $driver The event loop driver. If null a new one is created from the set factory. + * @param Driver $driver The event loop driver. If `null`, a new one is created from the set factory. * * @return void + * + * @see \Interop\Async\Loop::setFactory() */ public static function execute(callable $callback, Driver $driver = null) { @@ -79,19 +81,19 @@ public static function execute(callable $callback, Driver $driver = null) /** * Create a new driver if a factory is present, otherwise throw. * - * @throws \LogicException If no factory is set or no driver returned from factory. + * @throws \Exception If no factory is set or no driver returned from factory. */ private static function createDriver() { if (self::$factory === null) { - throw new \LogicException("No loop driver factory set; Either pass a driver to Loop::execute or set a factory."); + throw new \Exception("No loop driver factory set; Either pass a driver to Loop::execute or set a factory."); } $driver = self::$factory->create(); if (!$driver instanceof Driver) { $type = is_object($driver) ? "an instance of " . get_class($driver) : gettype($driver); - throw new \LogicException("Loop driver factory returned {$type}, but must return an instance of Driver."); + throw new \Exception("Loop driver factory returned {$type}, but must return an instance of Driver."); } return $driver; @@ -126,7 +128,7 @@ public static function stop() * Defer the execution of a callback. * * @param callable(string $watcherId, mixed $data) $callback The callback to defer. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. */ @@ -143,7 +145,7 @@ public static function defer(callable $callback, $data = null) * * @param int $time The amount of time, in milliseconds, to delay the execution for. * @param callable(string $watcherId, mixed $data) $callback The callback to delay. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. */ @@ -161,7 +163,7 @@ public static function delay($time, callable $callback, $data = null) * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. */ @@ -176,7 +178,7 @@ public static function repeat($interval, callable $callback, $data = null) * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. */ @@ -191,7 +193,7 @@ public static function onReadable($stream, callable $callback, $data = null) * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. */ @@ -205,11 +207,11 @@ public static function onWritable($stream, callable $callback, $data = null) * Execute a callback when a signal is received. * * WARNING: Installing a handler on the same signal on different scopes of event loop execution is - * undefined behavior and may break things arbitrarily. + * undefined behavior and may break things arbitrarily. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An identifier that can be used to cancel, enable or disable the watcher. * @@ -250,8 +252,10 @@ public static function disable($watcherId) } /** - * Cancel a watcher. This will detatch the event loop from all resources that are associated to the watcher. After - * this operation the watcher is permanently invalid. + * Cancel a watcher. + * + * This will detatch the event loop from all resources that are associated to the watcher. After this + * operation the watcher is permanently invalid. * * @param string $watcherId The watcher identifier. * @@ -266,8 +270,8 @@ public static function cancel($watcherId) /** * Reference a watcher. * - * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by - * default. + * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state + * by default. * * @param string $watcherId The watcher identifier. * @@ -284,8 +288,8 @@ public static function reference($watcherId) /** * Unreference a watcher. * - * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers - * are all referenced by default. + * The event loop should exit the run method when only unreferenced watchers are still being monitored. + * Watchers are all referenced by default. * * @param string $watcherId The watcher identifier. * @@ -300,13 +304,14 @@ public static function unreference($watcherId) } /** - * Stores information in the loop bound registry. This can be used to store loop bound information. Stored - * information is package private. Packages MUST NOT retrieve the stored state of other packages. + * Stores information in the loop bound registry. * - * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` + * This can be used to store loop bound information. Stored information is package private. Packages MUST NOT + * retrieve the stored state of other packages. Packages MUST use the following prefix to keys: + * `vendor.package.` * - * @param string $key namespaced storage key - * @param mixed $value the value to be stored + * @param string $key The namespaced storage key. + * @param mixed $value The value to be stored. * * @return void */ @@ -317,12 +322,12 @@ public static function setState($key, $value) } /** - * Gets information stored bound to the loop. Stored information is package private. Packages MUST NOT retrieve the - * stored state of other packages. + * Gets information stored bound to the loop. * - * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. + * Packages MUST use the following prefix to keys: `vendor.package.` * - * @param string $key namespaced storage key + * @param string $key The namespaced storage key. * * @return mixed previously stored value or null if it doesn't exist */ @@ -363,7 +368,7 @@ public static function setErrorHandler(callable $callback = null) * "watchers" => ["referenced" => int, "unreferenced" => int], * ]; * - * Implementations MAY optionally add more information in the array but at minimum the above key => value format + * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 3949adf..26c77e0 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -39,9 +39,9 @@ abstract public function stop(); * The deferred callable MUST be executed in the next tick of the event loop and before any other type of watcher. * Order of enabling MUST be preserved when executing the callbacks. * - * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The $watcherId will be + * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ @@ -51,12 +51,12 @@ abstract public function defer(callable $callback, $data = null); * Delay the execution of a callback. * * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which - * timers expire first, but timers with the same expiration time may be executed in any order. + * timers expire first, but timers with the same expiration time MAY be executed in any order. * * @param int $delay The amount of time, in milliseconds, to delay the execution for. - * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The $watcherId will be + * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ @@ -71,7 +71,7 @@ abstract public function delay($delay, callable $callback, $data = null); * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ @@ -84,7 +84,7 @@ abstract public function repeat($interval, callable $callback, $data = null); * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ @@ -97,7 +97,7 @@ abstract public function onReadable($stream, callable $callback, $data = null); * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ @@ -108,7 +108,7 @@ abstract public function onWritable($stream, callable $callback, $data = null); * * Multiple watchers on the same signal may be executed in any order. * - * NOTE: Installing a same signal on different instances of this interface is deemed undefined behavior. + * NOTE: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations may try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * @@ -126,7 +126,8 @@ abstract public function onSignal($signo, callable $callback, $data = null); * Enable a watcher. * * Watchers (enabling or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks - * can be called) right before the next tick. Callbacks of watchers MUST not be called in the tick they were enabled. + * can be called) right before the next tick. Callbacks of watchers MUST not be called in the tick they were + * enabled. * * @param string $watcherId The watcher identifier. * @@ -137,8 +138,10 @@ abstract public function onSignal($signo, callable $callback, $data = null); abstract public function enable($watcherId); /** - * Disable a watcher. Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, - * even if passed an invalid watcher. + * Disable a watcher. + * + * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an + * invalid watcher. * * @param string $watcherId The watcher identifier. * @@ -147,9 +150,10 @@ abstract public function enable($watcherId); abstract public function disable($watcherId); /** - * Cancel a watcher. This will detatch the event loop from all resources that are associated to the watcher. After - * this operation the watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an - * invalid watcher. + * Cancel a watcher. + * + * This will detatch the event loop from all resources that are associated to the watcher. After this operation the + * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * @@ -186,10 +190,10 @@ abstract public function reference($watcherId); abstract public function unreference($watcherId); /** - * Stores information in the loop bound registry. This can be used to store loop bound information. Stored - * information is package private. Packages MUST NOT retrieve the stored state of other packages. + * Stores information in the loop bound registry. * - * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` + * This can be used to store loop bound information. Stored information is package private. Packages MUST NOT + * retrieve the stored state of other packages. Packages MUST use the following prefix for keys: `vendor.package.` * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. @@ -206,14 +210,14 @@ final public function setState($key, $value) } /** - * Gets information stored bound to the loop. Stored information is package private. Packages MUST NOT retrieve the - * stored state of other packages. + * Gets information stored bound to the loop. * - * Therefore packages SHOULD use the following prefix to keys: `vendor.package.` + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use the following prefix for keys: `vendor.package.` * * @param string $key The namespaced storage key. * - * @return mixed The previously stored value or null if it doesn't exist. + * @return mixed The previously stored value or `null` if it doesn't exist. */ final public function getState($key) { @@ -225,8 +229,8 @@ final public function getState($key) * * Subsequent calls to this method will overwrite the previous handler. * - * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute; null will clear the current - * handler. + * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the + * current handler. * * @return void */ @@ -237,17 +241,17 @@ abstract public function setErrorHandler(callable $callback = null); * * The returned array MUST contain the following data describing the driver's currently registered watchers: * - * [ - * "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], - * "watchers" => ["referenced" => int, "unreferenced" => int], - * ]; - * - * Implementations MAY optionally add more information in the array but at minimum the above key => value format + * [ + * "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], + * "watchers" => ["referenced" => int, "unreferenced" => int], + * ]; + * + * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * * @return array @@ -257,12 +261,12 @@ abstract public function info(); /** * Get the underlying loop handle. * - * Example: the uv_loop resource for libuv or the EvLoop object for libev or null for a native driver. + * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver. * - * NOTE: This function is *not* exposed in the Loop class. Users shall access it directly on the respective loop + * NOTE: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop * instance. * - * @return null|object|resource The loop handle the event loop operates on. Null if there is none. + * @return null|object|resource The loop handle the event loop operates on. `null` if there is none. */ abstract public function getHandle(); } From 728d468432a889e21edb9c57cb0731f1c6e0cdc6 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Mon, 10 Oct 2016 10:54:27 +0200 Subject: [PATCH 07/30] Missing return type --- src/Loop.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Loop.php b/src/Loop.php index fa9593b..aaf9bc0 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -81,6 +81,8 @@ public static function execute(callable $callback, Driver $driver = null) /** * Create a new driver if a factory is present, otherwise throw. * + * @return Driver + * * @throws \Exception If no factory is set or no driver returned from factory. */ private static function createDriver() From 27e7f2a05b3434d1975142414a1a3319540ebf93 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Mon, 24 Oct 2016 20:43:21 +0200 Subject: [PATCH 08/30] Define error handler behavior Resolves #95. --- src/Loop.php | 8 ++++++-- src/Loop/Driver.php | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index aaf9bc0..9279574 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -342,10 +342,14 @@ public static function getState($key) /** * Set a callback to be executed when an error occurs. * + * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. + * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation + * MUST be thrown into the `run` loop and stop the driver. + * * Subsequent calls to this method will overwrite the previous handler. * - * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute; null will clear the current - * handler. + * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the + * current handler. * * @return void */ diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 26c77e0..4c69389 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -227,6 +227,10 @@ final public function getState($key) /** * Set a callback to be executed when an error occurs. * + * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. + * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation + * MUST be thrown into the `run` loop and stop the driver. + * * Subsequent calls to this method will overwrite the previous handler. * * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the From c1a4d9346d0bb87681b610191cef905909373e28 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Mon, 24 Oct 2016 17:08:53 +0200 Subject: [PATCH 09/30] Add warning about locally closed resources being undefined behavior Also makes Loop docs consistent with Driver. Resolves #106. --- src/Loop.php | 61 +++++++++++++++++++++++++++++++-------------- src/Loop/Driver.php | 18 ++++++++++--- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 9279574..fc173a2 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -178,11 +178,18 @@ public static function repeat($interval, callable $callback, $data = null) /** * Execute a callback when a stream resource becomes readable or is closed for reading. * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are + * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed + * resources are therefore undefined behavior. + * + * Multiple watchers on the same stream may be executed in any order. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onReadable($stream, callable $callback, $data = null) { @@ -193,11 +200,18 @@ public static function onReadable($stream, callable $callback, $data = null) /** * Execute a callback when a stream resource becomes writable or is closed for writing. * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are + * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed + * resources are therefore undefined behavior. + * + * Multiple watchers on the same stream may be executed in any order. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function onWritable($stream, callable $callback, $data = null) { @@ -208,16 +222,19 @@ public static function onWritable($stream, callable $callback, $data = null) /** * Execute a callback when a signal is received. * - * WARNING: Installing a handler on the same signal on different scopes of event loop execution is - * undefined behavior and may break things arbitrarily. + * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. + * Implementations may try to detect this, if possible, but are not required to. This is due to technical + * limitations of the signals being registered globally per process. + * + * Multiple watchers on the same signal may be executed in any order. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. - * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * @param mixed $data Arbitrary data given to the callback function as the $data parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. * - * @throws UnsupportedFeatureException Thrown if signal handling is not supported. + * @throws UnsupportedFeatureException If signal handling is not supported. */ public static function onSignal($signo, callable $callback, $data = null) { @@ -228,11 +245,15 @@ public static function onSignal($signo, callable $callback, $data = null) /** * Enable a watcher. * + * Watchers (enabling or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks + * can be called) right before the next tick. Callbacks of watchers MUST not be called in the tick they were + * enabled. + * * @param string $watcherId The watcher identifier. * * @return void * - * @throws InvalidWatcherException Thrown if the watcher identifier is invalid. + * @throws InvalidWatcherException If the watcher identifier is invalid. */ public static function enable($watcherId) { @@ -243,6 +264,9 @@ public static function enable($watcherId) /** * Disable a watcher. * + * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an + * invalid watcher. + * * @param string $watcherId The watcher identifier. * * @return void @@ -256,8 +280,8 @@ public static function disable($watcherId) /** * Cancel a watcher. * - * This will detatch the event loop from all resources that are associated to the watcher. After this - * operation the watcher is permanently invalid. + * This will detatch the event loop from all resources that are associated to the watcher. After this operation the + * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. * * @param string $watcherId The watcher identifier. * @@ -272,8 +296,8 @@ public static function cancel($watcherId) /** * Reference a watcher. * - * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state - * by default. + * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by + * default. * * @param string $watcherId The watcher identifier. * @@ -290,8 +314,8 @@ public static function reference($watcherId) /** * Unreference a watcher. * - * The event loop should exit the run method when only unreferenced watchers are still being monitored. - * Watchers are all referenced by default. + * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers + * are all referenced by default. * * @param string $watcherId The watcher identifier. * @@ -309,8 +333,7 @@ public static function unreference($watcherId) * Stores information in the loop bound registry. * * This can be used to store loop bound information. Stored information is package private. Packages MUST NOT - * retrieve the stored state of other packages. Packages MUST use the following prefix to keys: - * `vendor.package.` + * retrieve the stored state of other packages. Packages MUST use the following prefix for keys: `vendor.package.` * * @param string $key The namespaced storage key. * @param mixed $value The value to be stored. @@ -326,12 +349,12 @@ public static function setState($key, $value) /** * Gets information stored bound to the loop. * - * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. - * Packages MUST use the following prefix to keys: `vendor.package.` + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use the following prefix for keys: `vendor.package.` * * @param string $key The namespaced storage key. * - * @return mixed previously stored value or null if it doesn't exist + * @return mixed The previously stored value or `null` if it doesn't exist. */ public static function getState($key) { diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 4c69389..d0da80f 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -80,6 +80,11 @@ abstract public function repeat($interval, callable $callback, $data = null); /** * Execute a callback when a stream resource becomes readable or is closed for reading. * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are + * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed + * resources are therefore undefined behavior. + * * Multiple watchers on the same stream may be executed in any order. * * @param resource $stream The stream to monitor. @@ -93,6 +98,11 @@ abstract public function onReadable($stream, callable $callback, $data = null); /** * Execute a callback when a stream resource becomes writable or is closed for writing. * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are + * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed + * resources are therefore undefined behavior. + * * Multiple watchers on the same stream may be executed in any order. * * @param resource $stream The stream to monitor. @@ -106,12 +116,12 @@ abstract public function onWritable($stream, callable $callback, $data = null); /** * Execute a callback when a signal is received. * - * Multiple watchers on the same signal may be executed in any order. - * - * NOTE: Installing the same signal on different instances of this interface is deemed undefined behavior. + * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. * Implementations may try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * + * Multiple watchers on the same signal may be executed in any order. + * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. @@ -267,7 +277,7 @@ abstract public function info(); * * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver. * - * NOTE: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop + * Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop * instance. * * @return null|object|resource The loop handle the event loop operates on. `null` if there is none. From 5d9de0c060279a3a53bbb0c47a37c38903abaad8 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Mon, 24 Oct 2016 17:21:12 +0200 Subject: [PATCH 10/30] Fix typo, remove debug mode hint --- src/Loop.php | 12 ++++++------ src/Loop/Driver.php | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index fc173a2..8e50748 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -179,9 +179,9 @@ public static function repeat($interval, callable $callback, $data = null) * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are - * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed - * resources are therefore undefined behavior. + * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. * * Multiple watchers on the same stream may be executed in any order. * @@ -201,9 +201,9 @@ public static function onReadable($stream, callable $callback, $data = null) * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are - * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed - * resources are therefore undefined behavior. + * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. * * Multiple watchers on the same stream may be executed in any order. * diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index d0da80f..045db66 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -81,9 +81,9 @@ abstract public function repeat($interval, callable $callback, $data = null); * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are - * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed - * resources are therefore undefined behavior. + * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. * * Multiple watchers on the same stream may be executed in any order. * @@ -99,9 +99,9 @@ abstract public function onReadable($stream, callable $callback, $data = null); * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers might choose to notify the user in a debug mode if there are - * watchers on invalid resources, but are not required to, due to the high performance impact. Watchers on closed - * resources are therefore undefined behavior. + * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. * * Multiple watchers on the same stream may be executed in any order. * From 9916529f3c433ebcc32f61d09b2dd914922b5c17 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Tue, 25 Oct 2016 17:29:09 +0200 Subject: [PATCH 11/30] =?UTF-8?q?'may'=20=E2=86=92=20'MAY',=20copy=20docs?= =?UTF-8?q?=20for=20defer,=20delay,=20repeat=20from=20Driver=20to=20Loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Loop.php | 35 +++++++++++++++++++++-------------- src/Loop/Driver.php | 14 +++++++------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 8e50748..6c81530 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -129,10 +129,14 @@ public static function stop() /** * Defer the execution of a callback. * - * @param callable(string $watcherId, mixed $data) $callback The callback to defer. + * The deferred callable MUST be executed in the next tick of the event loop and before any other type of watcher. + * Order of enabling MUST be preserved when executing the callbacks. + * + * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be + * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function defer(callable $callback, $data = null) { @@ -143,13 +147,15 @@ public static function defer(callable $callback, $data = null) /** * Delay the execution of a callback. * - * The delay is a minimum and approximate, accuracy is not guaranteed. + * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which + * timers expire first, but timers with the same expiration time MAY be executed in any order. * - * @param int $time The amount of time, in milliseconds, to delay the execution for. - * @param callable(string $watcherId, mixed $data) $callback The callback to delay. + * @param int $delay The amount of time, in milliseconds, to delay the execution for. + * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be + * invalidated before the callback call. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function delay($time, callable $callback, $data = null) { @@ -160,14 +166,15 @@ public static function delay($time, callable $callback, $data = null) /** * Repeatedly execute a callback. * - * The interval between executions is a minimum and approximate, accuracy is not guaranteed. + * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be + * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. * - * @return string An identifier that can be used to cancel, enable or disable the watcher. + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. */ public static function repeat($interval, callable $callback, $data = null) { @@ -179,11 +186,11 @@ public static function repeat($interval, callable $callback, $data = null) * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * - * Multiple watchers on the same stream may be executed in any order. + * Multiple watchers on the same stream MAY be executed in any order. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. @@ -201,11 +208,11 @@ public static function onReadable($stream, callable $callback, $data = null) * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * - * Multiple watchers on the same stream may be executed in any order. + * Multiple watchers on the same stream MAY be executed in any order. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. @@ -223,10 +230,10 @@ public static function onWritable($stream, callable $callback, $data = null) * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. - * Implementations may try to detect this, if possible, but are not required to. This is due to technical + * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * - * Multiple watchers on the same signal may be executed in any order. + * Multiple watchers on the same signal MAY be executed in any order. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 045db66..0a22cb7 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -66,7 +66,7 @@ abstract public function delay($delay, callable $callback, $data = null); * Repeatedly execute a callback. * * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be - * determined by which timers expire first, but timers with the same expiration time may be executed in any order. + * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * * @param int $interval The time interval, in milliseconds, to wait between executions. @@ -81,11 +81,11 @@ abstract public function repeat($interval, callable $callback, $data = null); * Execute a callback when a stream resource becomes readable or is closed for reading. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * - * Multiple watchers on the same stream may be executed in any order. + * Multiple watchers on the same stream MAY be executed in any order. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. @@ -99,11 +99,11 @@ abstract public function onReadable($stream, callable $callback, $data = null); * Execute a callback when a stream resource becomes writable or is closed for writing. * * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the - * watcher when closing the resource locally. Drivers may choose to notify the user if there are watchers on invalid + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid * resources, but are not required to, due to the high performance impact. Watchers on closed resources are * therefore undefined behavior. * - * Multiple watchers on the same stream may be executed in any order. + * Multiple watchers on the same stream MAY be executed in any order. * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. @@ -117,10 +117,10 @@ abstract public function onWritable($stream, callable $callback, $data = null); * Execute a callback when a signal is received. * * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. - * Implementations may try to detect this, if possible, but are not required to. This is due to technical + * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical * limitations of the signals being registered globally per process. * - * Multiple watchers on the same signal may be executed in any order. + * Multiple watchers on the same signal MAY be executed in any order. * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. From f41eb23a8d1d2c00314912b94548601fa6077215 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 6 Nov 2016 18:38:20 +0100 Subject: [PATCH 12/30] Add InvalidWatcherException::getWatcherId Resolves #98. I guess this exception should only be thrown if the passed watcher identifier is a string. If a wrong type is passed, some other exception should be thrown. --- src/Loop/InvalidWatcherException.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Loop/InvalidWatcherException.php b/src/Loop/InvalidWatcherException.php index 80cdf7d..a80b20f 100644 --- a/src/Loop/InvalidWatcherException.php +++ b/src/Loop/InvalidWatcherException.php @@ -9,5 +9,29 @@ */ class InvalidWatcherException extends \Exception { + /** @var string */ + private $watcherId; + /** + * @param string $watcherId The watcher identifier. + * @param string|null $message The exception message. + */ + public function __construct($watcherId, $message = null) + { + $this->watcherId = $watcherId; + + if ($message === null) { + $message = "An invalid watcher idenfier has been used: '{$watcherId}'"; + } + + parent::__construct($message); + } + + /** + * @return string The watcher identifier. + */ + public function getWatcherId() + { + return $this->watcherId; + } } From aa07fb14552a0a110d1af31265b849044125fb96 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 6 Nov 2016 21:50:31 +0100 Subject: [PATCH 13/30] Make driver and loop docs consistent --- src/Loop.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Loop.php b/src/Loop.php index 6c81530..b788d4c 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -55,6 +55,10 @@ public static function setFactory(DriverFactory $factory = null) /** * Execute a callback within the scope of an event loop driver. * + * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an + * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an + * error handler or exceptions that would be passed to an error handler but none exists to handle them. + * * @param callable $callback The callback to execute. * @param Driver $driver The event loop driver. If `null`, a new one is created from the set factory. * @@ -118,6 +122,9 @@ public static function get() /** * Stop the event loop. * + * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls + * to stop MUST be ignored and MUST NOT raise an exception. + * * @return void */ public static function stop() From 5f3086ba9561b8860128ea4381adf10eb1bc8c7d Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Wed, 16 Nov 2016 14:14:10 +0100 Subject: [PATCH 14/30] Use parallel-lint for linting --- .travis.yml | 6 +++--- composer.json | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b756d3d..6f73ecf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,8 @@ cache: install: - composer install - - composer show + - composer show -t script: - - find -name "*.php" -not -path "./vendor/*" -print0 | xargs -n 1 -0 php -l - - $(php -r 'if (PHP_MAJOR_VERSION >= 7) echo "phpdbg -qrr"; else echo "php";') vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml + - php vendor/bin/parallel-lint --exclude vendor . + - php vendor/bin/phpunit --coverage-text diff --git a/composer.json b/composer.json index f553628..4ec1cf5 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,9 @@ "php": ">=5.5.0" }, "require-dev": { - "phpunit/phpunit": "^4|^5" + "phpunit/phpunit": "^4|^5", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "jakub-onderka/php-console-highlighter": "^0.3.2" }, "autoload": { "psr-4": { From 438ce0b89275cf70032a517e3b6c4071336f85f2 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 18 Dec 2016 12:31:02 +0100 Subject: [PATCH 15/30] Add implementations and compatible projects to README Closes #105. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 9b86b55..af30526 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,14 @@ The functionality exposed by this interface should include the ability to: - Listen for signals - Defer the execution of callables +## Implementations + +You can find [available implementations on Packagist](https://packagist.org/providers/async-interop/event-loop-implementation). + +## Compatible Packages + +You can find [compatible packages on Packagist](https://packagist.org/packages/async-interop/event-loop/dependents). + ## Contributors * [Aaron Piotrowski](https://github.com/trowski) From 44fd40af9332d5d45a25f631cfd529e24207282c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 22 Dec 2016 17:50:25 +0100 Subject: [PATCH 16/30] Loop::setErrorHandler should return the last error handler --- src/Loop.php | 4 ++-- src/Loop/Driver.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index b788d4c..8c4fb1a 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -388,12 +388,12 @@ public static function getState($key) * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the * current handler. * - * @return void + * @return callable(\Throwable|\Exception $error)|null The previous handler, `null` if there was none. */ public static function setErrorHandler(callable $callback = null) { $driver = self::$driver ?: self::get(); - $driver->setErrorHandler($callback); + return $driver->setErrorHandler($callback); } /** diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 0a22cb7..5aa41e1 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -246,7 +246,7 @@ final public function getState($key) * @param callable(\Throwable|\Exception $error)|null $callback The callback to execute. `null` will clear the * current handler. * - * @return void + * @return callable(\Throwable|\Exception $error)|null The previous handler, `null` if there was none. */ abstract public function setErrorHandler(callable $callback = null); From 53bd12bbbd68a678d62af14b2720449b9aad8ad7 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 23 Dec 2016 10:58:26 +0100 Subject: [PATCH 17/30] Rename Loop::info to Loop::getInfo We use `get` for all other similar methods, too. Closes #102. --- src/Loop.php | 4 ++-- src/Loop/Driver.php | 2 +- test/DummyDriver.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 8c4fb1a..caae384 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -416,10 +416,10 @@ public static function setErrorHandler(callable $callback = null) * * @return array */ - public static function info() + public static function getInfo() { $driver = self::$driver ?: self::get(); - return $driver->info(); + return $driver->getInfo(); } /** diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 5aa41e1..ca2f763 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -270,7 +270,7 @@ abstract public function setErrorHandler(callable $callback = null); * * @return array */ - abstract public function info(); + abstract public function getInfo(); /** * Get the underlying loop handle. diff --git a/test/DummyDriver.php b/test/DummyDriver.php index 66e6037..c2ee069 100644 --- a/test/DummyDriver.php +++ b/test/DummyDriver.php @@ -43,6 +43,6 @@ public function disable($watcherId) {} public function cancel($watcherId) {} public function reference($watcherId) {} public function unreference($watcherId) {} - public function info() {} + public function getInfo() {} public function getHandle() {} } From 5eeb96ab800fb29d650c0453bdfe773c2b8692ef Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 23 Dec 2016 11:05:37 +0100 Subject: [PATCH 18/30] Add missing return description to Loop::getInfo --- src/Loop.php | 2 +- src/Loop/Driver.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index caae384..1990697 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -414,7 +414,7 @@ public static function setErrorHandler(callable $callback = null) * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * - * @return array + * @return array Statistics about the loop in the described format. */ public static function getInfo() { diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index ca2f763..50041f1 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -268,7 +268,7 @@ abstract public function setErrorHandler(callable $callback = null); * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format * MUST always be provided. * - * @return array + * @return array Statistics about the loop in the described format. */ abstract public function getInfo(); From 26173a63e648ee89e575d9c2797222029fcebece Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Wed, 28 Dec 2016 14:18:14 +0100 Subject: [PATCH 19/30] Add note about weak type requirement --- src/Loop/Driver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 50041f1..0add001 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -4,6 +4,8 @@ /** * Event loop driver which implements all basic operations to allow interoperability. + * + * Registered callbacks MUST NOT be called from a file with strict types enabled (`declare(strict_types=1)`). */ abstract class Driver { From 07246e1d0d1bffbbffa2590614e05402252f5206 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sat, 31 Dec 2016 19:50:39 +0100 Subject: [PATCH 20/30] Change proposal to specification --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index af30526..0bd090c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Event Loop Interopability -The purpose of this proposal is to provide a common interface for event loop -implementations. This will allow libraries and components from different -vendors to operate in an event driven architecture, sharing a common event -loop. +The purpose of this specification is to provide a common interface for +event loop implementations. This allows libraries and components from +different vendors to operate in an event driven architecture, sharing a +common event loop. ## Why Bother? @@ -12,7 +12,7 @@ native to the execution environment. This allows package vendors to easily create asynchronous software that uses this native event loop. Although PHP is historically a synchronous programming environment, it is still possible to use asynchronous programming techniques. Using these techniques, package -vendors have created PHP event loop implementations that have seen success. +vendors have created event loop implementations that have seen success. However, as these event loop implementations are from package vendors, it is not yet possible to create event driven software components that are From b9b49b3eaff7bd1107d4075b0cdd107d7fa3bd7c Mon Sep 17 00:00:00 2001 From: Josh Di Fabio Date: Mon, 2 Jan 2017 20:48:48 +0000 Subject: [PATCH 21/30] Change namespace to AsyncInterop\Loop --- composer.json | 4 ++-- src/Loop.php | 14 +++++++------- src/Loop/Driver.php | 2 +- src/Loop/DriverFactory.php | 4 ++-- src/Loop/InvalidWatcherException.php | 2 +- src/Loop/UnsupportedFeatureException.php | 2 +- test/DummyDriver.php | 4 ++-- test/LoopStateTest.php | 2 +- test/LoopTest.php | 4 ++-- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 4ec1cf5..b47d6e4 100644 --- a/composer.json +++ b/composer.json @@ -13,12 +13,12 @@ }, "autoload": { "psr-4": { - "Interop\\Async\\": "src" + "AsyncInterop\\": "src" } }, "autoload-dev": { "psr-4": { - "Interop\\Async\\Loop\\Test\\": "test" + "AsyncInterop\\Loop\\Test\\": "test" } } } diff --git a/src/Loop.php b/src/Loop.php index 1990697..f55db4f 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -1,16 +1,16 @@ Date: Tue, 3 Jan 2017 18:16:50 +0000 Subject: [PATCH 22/30] Fix typo 'idenfier' --- src/Loop/InvalidWatcherException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loop/InvalidWatcherException.php b/src/Loop/InvalidWatcherException.php index a80b20f..e1878c0 100644 --- a/src/Loop/InvalidWatcherException.php +++ b/src/Loop/InvalidWatcherException.php @@ -21,7 +21,7 @@ public function __construct($watcherId, $message = null) $this->watcherId = $watcherId; if ($message === null) { - $message = "An invalid watcher idenfier has been used: '{$watcherId}'"; + $message = "An invalid watcher identifier has been used: '{$watcherId}'"; } parent::__construct($message); From b5842db18b6913c4a8583019a10af010aae0c2aa Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 8 Jan 2017 11:40:11 +0100 Subject: [PATCH 23/30] =?UTF-8?q?watchers=20=E2=86=92=20enabled=5Fwatchers?= =?UTF-8?q?=20in=20getInfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures it's clear which info is returned. --- src/Loop.php | 14 +++++++------- src/Loop/Driver.php | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index f55db4f..76f54d3 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -402,13 +402,13 @@ public static function setErrorHandler(callable $callback = null) * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ - * "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], - * "watchers" => ["referenced" => int, "unreferenced" => int], + * "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], * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index fda1604..2526495 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -258,13 +258,13 @@ abstract public function setErrorHandler(callable $callback = null); * The returned array MUST contain the following data describing the driver's currently registered watchers: * * [ - * "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], - * "watchers" => ["referenced" => int, "unreferenced" => int], + * "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], * ]; * * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format From 5cbc42d6d98bdb71f3b9bea5837cacf8ea56e300 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 13 Jan 2017 15:14:01 +0100 Subject: [PATCH 24/30] Define 'tick' --- src/Loop/Driver.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 2526495..9dadf34 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -15,7 +15,14 @@ abstract class Driver private $registry = []; /** - * Start the event loop. + * Runs the event loop. + * + * One iteration of the loop is called one "tick". A tick covers the following steps: + * + * 1. Activate watchers created / enabled in the last tick / before `run`. + * 2. Execute all enabled defer watchers. + * 3. Execute all due timers, each timer only once per tick. + * 4. Execute actionable stream watchers, each only once per tick. * * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an From 6884501aac78c979f3846d1f25c150c5b4069e31 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 13 Jan 2017 15:15:55 +0100 Subject: [PATCH 25/30] Fix typo --- src/Loop/Driver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 9dadf34..4883d11 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -15,7 +15,7 @@ abstract class Driver private $registry = []; /** - * Runs the event loop. + * Run the event loop. * * One iteration of the loop is called one "tick". A tick covers the following steps: * From 7f3a0db4c92a8db3ed14b579d87854966c781eb3 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Fri, 20 Jan 2017 16:20:23 +0100 Subject: [PATCH 26/30] Remove timer / io callback order --- src/Loop/Driver.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 4883d11..c5de3fc 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -19,10 +19,9 @@ abstract class Driver * * One iteration of the loop is called one "tick". A tick covers the following steps: * - * 1. Activate watchers created / enabled in the last tick / before `run`. + * 1. Activate watchers created / enabled in the last tick / before `run()`. * 2. Execute all enabled defer watchers. - * 3. Execute all due timers, each timer only once per tick. - * 4. Execute actionable stream watchers, each only once per tick. + * 3. Execute all due timer and actionable stream callbacks, each only once per tick. * * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an From f648dd50e8008f68f4e5c7a9dd1019dd3a0cd51b Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Sun, 22 Jan 2017 17:09:35 +0100 Subject: [PATCH 27/30] Add pending signals to third tick step --- src/Loop/Driver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index c5de3fc..6595ce3 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -21,7 +21,7 @@ abstract class Driver * * 1. Activate watchers created / enabled in the last tick / before `run()`. * 2. Execute all enabled defer watchers. - * 3. Execute all due timer and actionable stream callbacks, each only once per tick. + * 3. Execute all due timer, pending signal and actionable stream callbacks, each only once per tick. * * The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an From c2b598ee9ce31bac32f82ae8d020e563914c0570 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Thu, 9 Feb 2017 09:50:23 +0100 Subject: [PATCH 28/30] Improve enable() doc and mention it also in the class level phpdoc block --- src/Loop.php | 5 ++--- src/Loop/Driver.php | 10 ++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 76f54d3..6126d56 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -259,9 +259,8 @@ public static function onSignal($signo, callable $callback, $data = null) /** * Enable a watcher. * - * Watchers (enabling or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks - * can be called) right before the next tick. Callbacks of watchers MUST not be called in the tick they were - * enabled. + * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before + * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 6595ce3..4a51fee 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -5,7 +5,10 @@ /** * Event loop driver which implements all basic operations to allow interoperability. * - * Registered callbacks MUST NOT be called from a file with strict types enabled (`declare(strict_types=1)`). + * Watchers (enabled or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks can + * be called) right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * All registered callbacks MUST NOT be called from a file with strict types enabled (`declare(strict_types=1)`). */ abstract class Driver { @@ -143,9 +146,8 @@ abstract public function onSignal($signo, callable $callback, $data = null); /** * Enable a watcher. * - * Watchers (enabling or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks - * can be called) right before the next tick. Callbacks of watchers MUST not be called in the tick they were - * enabled. + * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before + * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param string $watcherId The watcher identifier. * From 8eb3033c1c51310181c8e672ab7f82f3eddd7515 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Thu, 9 Feb 2017 15:47:44 +0100 Subject: [PATCH 29/30] Add note about watchers being enabled by default to every method creating a watcher --- src/Loop.php | 29 +++++++++++++++++++++++++---- src/Loop/Driver.php | 29 +++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/Loop.php b/src/Loop.php index 6126d56..27ddf28 100644 --- a/src/Loop.php +++ b/src/Loop.php @@ -136,8 +136,11 @@ public static function stop() /** * Defer the execution of a callback. * - * The deferred callable MUST be executed in the next tick of the event loop and before any other type of watcher. - * Order of enabling MUST be preserved when executing the callbacks. + * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be + * preserved when executing the callbacks. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. @@ -157,6 +160,9 @@ public static function defer(callable $callback, $data = null) * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. @@ -177,6 +183,9 @@ public static function delay($time, callable $callback, $data = null) * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -199,6 +208,9 @@ public static function repeat($interval, callable $callback, $data = null) * * Multiple watchers on the same stream MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -221,6 +233,9 @@ public static function onReadable($stream, callable $callback, $data = null) * * Multiple watchers on the same stream MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -242,6 +257,9 @@ public static function onWritable($stream, callable $callback, $data = null) * * Multiple watchers on the same signal MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. @@ -257,7 +275,7 @@ public static function onSignal($signo, callable $callback, $data = null) } /** - * Enable a watcher. + * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. @@ -275,7 +293,10 @@ public static function enable($watcherId) } /** - * Disable a watcher. + * Disable a watcher immediately. + * + * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer + * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. diff --git a/src/Loop/Driver.php b/src/Loop/Driver.php index 4a51fee..669e296 100644 --- a/src/Loop/Driver.php +++ b/src/Loop/Driver.php @@ -47,8 +47,11 @@ abstract public function stop(); /** * Defer the execution of a callback. * - * The deferred callable MUST be executed in the next tick of the event loop and before any other type of watcher. - * Order of enabling MUST be preserved when executing the callbacks. + * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be + * preserved when executing the callbacks. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. * * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be * invalidated before the callback call. @@ -64,6 +67,9 @@ abstract public function defer(callable $callback, $data = null); * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which * timers expire first, but timers with the same expiration time MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $delay The amount of time, in milliseconds, to delay the execution for. * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be * invalidated before the callback call. @@ -80,6 +86,9 @@ abstract public function delay($delay, callable $callback, $data = null); * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. * The first execution is scheduled after the first interval period. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $interval The time interval, in milliseconds, to wait between executions. * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -98,6 +107,9 @@ abstract public function repeat($interval, callable $callback, $data = null); * * Multiple watchers on the same stream MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -116,6 +128,9 @@ abstract public function onReadable($stream, callable $callback, $data = null); * * Multiple watchers on the same stream MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param resource $stream The stream to monitor. * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. @@ -133,6 +148,9 @@ abstract public function onWritable($stream, callable $callback, $data = null); * * Multiple watchers on the same signal MAY be executed in any order. * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * * @param int $signo The signal number to monitor. * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. * @param mixed $data Arbitrary data given to the callback function as the $data parameter. @@ -144,7 +162,7 @@ abstract public function onWritable($stream, callable $callback, $data = null); abstract public function onSignal($signo, callable $callback, $data = null); /** - * Enable a watcher. + * Enable a watcher to be active starting in the next tick. * * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. @@ -158,7 +176,10 @@ abstract public function onSignal($signo, callable $callback, $data = null); abstract public function enable($watcherId); /** - * Disable a watcher. + * Disable a watcher immediately. + * + * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer + * watcher isn't executed in this tick. * * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an * invalid watcher. From 67aa45579edf9a11d2122cd2d8c3c5ee46ea02d7 Mon Sep 17 00:00:00 2001 From: Niklas Keller Date: Thu, 16 Mar 2017 19:51:09 +0100 Subject: [PATCH 30/30] Add current status to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0bd090c..bc66f8c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ event loop implementations. This allows libraries and components from different vendors to operate in an event driven architecture, sharing a common event loop. +## Current Status + +This project is currently on hold and to be seen as failed for now. It might be reconsidered at a later point in time. The specification in its current state has been merged into [Amp](https://github.com/amphp/amp). Interoperability between [ReactPHP](https://github.com/reactphp/event-loop) and Amp will be solved via adapters instead of a common interface. [Icicle](https://github.com/icicleio/icicle) has been deprecated and parts of it been merged into Amp libraries. + ## Why Bother? Some programming languages, such as Javascript, have an event loop that is