[php-src] PR #25135: Fix the WSAPoll backend of Io\Poll accepting handles that are not sockets
| From: | nicolas-grekas | Date: | Sun, 01 Nov 2026 19:08:30 +0000 |
| Subject: | [php-src] PR #25135: Fix the WSAPoll backend of Io\Poll accepting handles that are not sockets | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-40197@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/25135
Author: nicolas-grekas
Found in [revoltphp/event-loop#135](https://github.com/revoltphp/event-loop/pull/135), where the
Windows CI hangs on callbacks on
STDOUT.
WSAPoll() can only poll sockets, but the WSAPoll backend accepts any fd. Files and
pipes give a CRT fd, so Context::add() succeeds for them. Then WSAPoll()
reports POLLNVAL for them, or fails with WSAENOTSOCK when they're
alone. In both cases wait() drops them and returns at once. The watcher is never
reported:
```php
// STDOUT is a pipe
$ctx = new Io\Poll\Context();
$ctx->add(new StreamPollHandle(STDOUT), [Io\Poll\Event::Write]); // no exception
$ctx->wait(); // returns [] at once, and again on every call
```
This PR checks the fd with getsockopt(SO_TYPE) in add(), the way
stream_select() tells sockets apart on Windows. Anything else fails with
ERROR_NOSUPPORT, as #23805 does for epoll. An event loop can then catch the
FailedHandleAddException and fall back to stream_select(). Revolt
doesn't pick its Io\Poll driver on Windows for now because of this.
I left the WSAENOTSOCK branch of wait() as is. This branch now only sees
sockets that were closed after being added. It drops those sockets like the poll backend drops
POLLNVAL.
/cc @bukka