[IoPoll] Polyfill the Io\Poll API#612
Conversation
7e4b509 to
b1dd831
Compare
78ff76a to
789a5dd
Compare
|
@symfony/mergers this one is ready for review! |
alexandre-daubois
left a comment
There was a problem hiding this comment.
Nothing to say on my side, looks good!
| if (Event::Write === $event) { | ||
| $write[$id] = $stream; | ||
| break; | ||
| } |
There was a problem hiding this comment.
When no handles are registered and $timeoutSeconds === null (infinite wait), the polyfill returns [] immediately without blocking. Native PHP's wait(null) blocks indefinitely regardless of how many handles are registered.
This is probably an unavoidable limitation of a pure-PHP polyfill, but it should be documented — a note in the README and/or a // Note: ... comment here so callers are not surprised.
There was a problem hiding this comment.
This one is backend-dependent in native, and the polyfill matches the backend it emulates. The poll, wsapoll and eventport backends explicitly guard the empty set and return immediately on a null timeout — e.g. poll_backend_poll.c:
int fd_count = php_poll_fd_table_count(backend_data->fd_table);
if (fd_count == 0) {
if (timeout != NULL && (timeout->tv_sec > 0 || timeout->tv_nsec > 0)) {
nanosleep(timeout, NULL);
}
return 0;
}Only epoll and kqueue lack that guard and block indefinitely on an empty set. Since the polyfill is the Poll backend (getBackend() === Backend::Poll), its immediate return matches native-poll exactly, so there's no divergence for the emulated backend — I've dropped the README/comment note I'd briefly added.
The epoll/kqueue side looks like an upstream inconsistency (those two arguably want the same zero-fd guard the poll family has); we may raise it with the RFC author separately.
789a5dd to
79729e5
Compare
3129891 to
1c929ed
Compare
3523f7b to
c32e070
Compare
|
Status update on the changes pushed since the first review round: Review fixes (amended into the first commit)
Native-parity rework (
Remaining divergences, documented in the component README: a TCP half-close reports Package split ( Tests went from 35 to 64, CI is green on the whole 7.2-8.6 matrix. |
|
Now with phpt borrowed from php-src Note the proposal: split this into its own |
4f5b9ac to
d441170
Compare
GromNaN
left a comment
There was a problem hiding this comment.
Given the size of the package and the specific constraints, splitting it into a separate package makes sense.
Thank you for the work you put into creating this polyfill; I can't wait to start using it.
|
Thank you @nicolas-grekas. |
Tracks the Polling API RFC targeted at PHP 8.6.
Shipped as a dedicated
symfony/polyfill-io-pollpackage (src/Io/Poll/), requiring PHP >= 8.1 (enums); the split repository and Packagist entry will need to be created before the next release. Surface:Io\IoException,Io\Poll\PollException, abstractFailedPollOperationException(withERROR_*constants), and the seven specialized exceptions (Failed{ContextInitialization,HandleAdd,WatcherModification,PollWait}Exception,BackendUnavailableException,InactiveWatcherException,HandleAlreadyWatchedException,InvalidHandleException).Io\Poll\Backendenum withAuto,Poll,Epoll,Kqueue,EventPorts,WSAPollcases andisAvailable()/supportsEdgeTriggering()/getAvailableBackends().Io\Poll\Eventenum withRead,Write,Error,HangUp,ReadHangUp,OneShot,EdgeTriggered.Io\Poll\Handlemarker interface (annotated@internalto discourage userland implementations).Io\Poll\Context,Io\Poll\Watcher, and globalStreamPollHandle, with private constructors, clone/double-construct/serialization guards throwing the native errors, and empty__debugInfo()like native; the watcher references its context through aWeakReferenceso that destroying the context deactivates its watchers like native refcounting does.Backed by
stream_select(), so only thePollbackend is available;Autoresolves to it and the other backends throwBackendUnavailableException. Behavior mirrors the nativepollbackend ofio_poll.c/poll_backend_poll.c: exception messages and codes match,Event::EdgeTriggeredis rejected withERROR_NOSUPPORT, closed streams are dropped likePOLLNVAL, a firedOneShotwatcher stays active withmodify*()throwingERROR_NOTFOUND,HangUp(detected withstream_socket_recvfrom(..., STREAM_PEEK)andfeof()) is reported alongsideReadlikePOLLIN|POLLHUP, even when not watched, and never for regular files or datagram sockets, and a connection reset (peer closed with unread data, detected when peeking a readable socket fails) reportsError|HangUplikePOLLERR|POLLHUP.Event::ReadHangUpis never emitted, matching the nativepollbackend. Known divergences are documented in the component README: TCP half-close reportsRead|HangUpwhere native reports plainRead.The test suite combines 64 unit tests with the 28 phpt tests of the native implementation, borrowed verbatim from php-src (
ext/standard/tests/poll) and executed against the polyfill through a small PHPUnit runner; the phpt suite resolves its backend-specific expectations against thePollbackend, which is exactly what the polyfill emulates.