Skip to content

Commit

Permalink
feat(async): throw if resource is closed while waiting
Browse files Browse the repository at this point in the history
Signed-off-by: azjezz <azjezz@protonmail.com>
  • Loading branch information
azjezz committed Nov 6, 2021
1 parent e692cc4 commit 3688e72
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 18 deletions.
9 changes: 9 additions & 0 deletions src/Psl/Async/Exception/ResourceClosedException.php
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Psl\Async\Exception;

final class ResourceClosedException extends RuntimeException
{
}
11 changes: 11 additions & 0 deletions src/Psl/Async/await_readable.php
Expand Up @@ -4,14 +4,19 @@

namespace Psl\Async;

use Psl\Async\Exception\ResourceClosedException;
use Revolt\EventLoop;
use Throwable;

use function is_resource;

/**
* Wait for the given resource to become readable in a non-blocking way.
*
* @param resource|object $resource
*
* @throws Exception\TimeoutException If $timeout is non-null, and the operation timed-out.
* @throws Exception\ResourceClosedException If $resource was closed before it became readable.
*
* @codeCoverageIgnore
*/
Expand All @@ -36,6 +41,12 @@ function await_readable(mixed $resource, bool $reference = true, ?float $timeout

try {
$suspension->suspend();
} catch (Throwable $e) {
if (!is_resource($resource)) {
throw new ResourceClosedException('Resource was closed before it became readable.');
}

throw $e;
} finally {
Scheduler::cancel($watcher);

Expand Down
8 changes: 8 additions & 0 deletions src/Psl/Async/await_writable.php
Expand Up @@ -4,7 +4,9 @@

namespace Psl\Async;

use Psl\Async\Exception\ResourceClosedException;
use Revolt\EventLoop;
use Throwable;

/**
* Wait for the given resource to become writable in a non-blocking way.
Expand Down Expand Up @@ -36,6 +38,12 @@ function await_writable(mixed $resource, bool $reference = true, ?float $timeout

try {
$suspension->suspend();
} catch (Throwable $e) {
if (!is_resource($resource)) {
throw new ResourceClosedException('Resource was closed before it became writable.');
}

throw $e;
} finally {
Scheduler::cancel($watcher);

Expand Down
24 changes: 6 additions & 18 deletions src/Psl/Async/main.php
Expand Up @@ -4,35 +4,23 @@

namespace Psl\Async;

use Throwable;

/**
* Execute the given callable in an async context, then exit with returned exit code.
*
* If the callable returns an awaitable, the awaitable *MUST* resolve with an exit code.
*
* @param (callable(): int)|(callable(): Awaitable<int>) $callable
* @param (callable(): int)|(callable(): Awaitable<int>)|(callable(): never)|(callable(): Awaitable<never>) $callable
*
* @codeCoverageIgnore
*/
function main(callable $callable): never
{
$main = Scheduler::createSuspension();

Scheduler::defer(static function () use ($callable, $main): void {
try {
$exit_code = $callable();
$main->resume($exit_code);
} catch (Throwable $throwable) {
$main->throw($throwable);
}
});
later();

/** @var int|Awaitable<int> $return */
$return = $main->suspend();
if ($return instanceof Awaitable) {
$return = $return->await();
$result = $callable();
if ($result instanceof Awaitable) {
$result = $result->await();
}

exit($return);
exit($result);
}
8 changes: 8 additions & 0 deletions src/Psl/IO/Internal/ResourceHandle.php
Expand Up @@ -124,6 +124,10 @@ public function write(string $bytes, ?float $timeout = null): int
Async\await_writable($this->resource, timeout: $timeout);
} catch (Async\Exception\TimeoutException) {
throw new Exception\TimeoutException('reached timeout while the handle is still not writable.');
} catch (Async\Exception\ResourceClosedException) {
$this->resource = null;

throw new Exception\AlreadyClosedException('Handle has already been closed.');
}

return $written + $this->writeImmediately($bytes);
Expand Down Expand Up @@ -215,6 +219,10 @@ public function read(?int $max_bytes = null, ?float $timeout = null): string
Async\await_readable($this->resource, timeout: $timeout);
} catch (Async\Exception\TimeoutException) {
throw new Exception\TimeoutException('reached timeout while the handle is still not readable.');
} catch (Async\Exception\ResourceClosedException) {
$this->resource = null;

throw new Exception\AlreadyClosedException('Handle has already been closed.');
}

return $this->readImmediately($max_bytes);
Expand Down

0 comments on commit 3688e72

Please sign in to comment.