Commit 0278788facf for php
commit 0278788facf75c8cb232127887cc8692273b958f
Merge: 78a21e9fd5b 954f79636e4
Author: Jakub Zelenka <bukka@php.net>
Date: Sun Nov 1 21:29:04 2026 +0100
Merge branch 'PHP-8.6'
* PHP-8.6:
Report Io\Poll level watchers with buffered stream data (#24017)
diff --cc ext/standard/io_poll.c
index c2585a51d3c,583dfdbc033..ae6d5a4c984
--- a/ext/standard/io_poll.c
+++ b/ext/standard/io_poll.c
@@@ -239,8 -243,19 +243,19 @@@ static php_poll_handle_ops php_stream_p
.cleanup = php_stream_poll_handle_cleanup
};
+ /* The stream buffer only, without any IO */
+ static bool php_stream_poll_handle_has_buffered_data(php_poll_handle_object *handle)
+ {
+ php_stream *stream = php_stream_poll_handle_get_stream(handle);
+ return stream && stream->writepos > stream->readpos;
+ }
+
+ static const php_poll_handle_ext_ops php_stream_poll_handle_ext_ops = {
+ .has_buffered_data = php_stream_poll_handle_has_buffered_data
+ };
+
/* Handle interface internal only */
-static int php_stream_poll_handle_implement_interface(zend_class_entry *interface, zend_class_entry *implementor)
+static void php_stream_poll_handle_implement_interface(zend_class_entry *interface, zend_class_entry *implementor)
{
if (implementor->type == ZEND_USER_CLASS) {
zend_error_noreturn(E_ERROR, "Io\\Poll\\Handle cannot be implemented by user classes");
@@@ -885,25 -923,87 +919,83 @@@ PHP_METHOD(Io_Poll_Context, wait
RETURN_THROWS();
}
- php_poll_event *events = safe_emalloc((size_t) max_events, sizeof(*events), 0);
- int num_events = php_poll_wait(intern->ctx, events, (int) max_events, timeout ? &timeout_ts : NULL);
+ /* Buffered watchers go first, then a non-blocking backend check */
+ php_io_poll_watcher_object **buffered = NULL;
+ int n_buffered = 0;
+ if (intern->buffered_readers) {
+ ZEND_HASH_FOREACH_VAL(intern->watchers, zval *zv) {
+ php_io_poll_watcher_object *watcher = PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(Z_OBJ_P(zv));
+ if (watcher->disarmed || !php_io_poll_watcher_reads_buffered(watcher)
+ || !watcher->ext_ops->has_buffered_data(watcher->handle)) {
+ continue;
+ }
+ if (!buffered) {
+ buffered = safe_emalloc((size_t) max_events, sizeof(*buffered), 0);
+ }
+ buffered[n_buffered++] = watcher;
+ if (n_buffered == max_events) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
- if (num_events < 0) {
- php_poll_error err = php_poll_get_error(intern->ctx);
- efree(events);
- php_io_poll_throw_failed_operation(
- php_io_poll_failed_wait_class_entry, "Poll wait failed", err);
- RETURN_THROWS();
+ php_poll_event *events = safe_emalloc((size_t) max_events, sizeof(*events), 0);
+ int num_events = 0;
+ if (n_buffered < max_events) {
+ struct timespec zero_ts = {0, 0};
+ num_events = php_poll_wait(intern->ctx, events, (int) max_events - n_buffered,
+ n_buffered ? &zero_ts : (timeout ? &timeout_ts : NULL));
+ if (num_events < 0) {
+ php_poll_error err = php_poll_get_error(intern->ctx);
+ if (n_buffered == 0 || err != PHP_POLL_ERR_INTERRUPTED) {
+ efree(events);
+ if (buffered) {
+ efree(buffered);
+ }
+ php_io_poll_throw_failed_operation(
+ php_io_poll_failed_wait_class_entry, "Poll wait failed", err);
+ RETURN_THROWS();
+ }
+ /* The buffered data is the result */
+ num_events = 0;
+ }
}
- array_init(return_value);
+ array_init_size(return_value, (uint32_t) (n_buffered + num_events));
+
+ for (int i = 0; i < n_buffered; i++) {
+ php_io_poll_watcher_object *watcher = buffered[i];
+ watcher->triggered_events = PHP_POLL_READ;
+ watcher->reported = true;
+
- zval watcher_zv;
- ZVAL_OBJ_COPY(&watcher_zv, &watcher->std);
- add_next_index_zval(return_value, &watcher_zv);
++ add_next_index_object(return_value, zend_object_copy(&watcher->std));
+ }
for (int i = 0; i < num_events; i++) {
php_io_poll_watcher_object *watcher = (php_io_poll_watcher_object *) events[i].data;
- if (watcher) {
- watcher->triggered_events = events[i].revents;
+ if (!watcher) {
+ continue;
+ }
+ if (watcher->watched_events & PHP_POLL_ONESHOT) {
+ watcher->disarmed = true;
+ }
+ if (watcher->reported) {
+ /* Already reported from its buffer */
+ watcher->triggered_events |= events[i].revents;
+ continue;
+ }
+ watcher->triggered_events = events[i].revents;
- add_next_index_object(return_value, zend_object_copy(&watcher->std));
- zval watcher_zv;
- ZVAL_OBJ_COPY(&watcher_zv, &watcher->std);
- add_next_index_zval(return_value, &watcher_zv);
++ add_next_index_object(return_value, zend_object_copy(&watcher->std));
+ }
+
+ /* Reset the per-wait flag. A buffer-only one-shot is still armed in the backend */
+ for (int i = 0; i < n_buffered; i++) {
+ php_io_poll_watcher_object *watcher = buffered[i];
+ watcher->reported = false;
+ if ((watcher->watched_events & PHP_POLL_ONESHOT) && !watcher->disarmed) {
+ watcher->disarmed = true;
+ php_poll_remove(intern->ctx, (int) watcher->fd);
}
}