Skip to content

Conversation

@EdmondDantes
Copy link

No description provided.

EdmondDantes and others added 7 commits February 5, 2026 17:49
Introduce zend_async_io_req_t — a one-shot request object returned by
IO functions instead of blocking the coroutine. Backend allocates the
request, starts the async operation, and returns immediately. The caller
(plain_wrapper) decides whether to suspend via waker/event subscription.

API changes:
- read/write/flush/stat return zend_async_io_req_t* instead of ssize_t/int
- read takes (io, max_size) — backend allocates the buffer
- req has completed flag for instant completions (EOF, pipe flush/stat)
- req->dispose() handles cleanup (buf, exception, req itself)

plain_wrapper integration:
- php_stdiop_read/write check req->completed before suspending
- Waker-based suspend/resume for async operations
- Exception propagation for both sync and async error paths
When ZEND_ASYNC_IO_CLOSE for a pipe handle returns fd_closed=1,
both data->fd and data->file are set to -1/NULL. The subsequent
close_handle block then hits the else branch which had an early
`return 0`, skipping pefree(data) and leaking the 128-byte
php_stdio_stream_data structure. Replace the early return with
`ret = 0` so execution reaches pefree.
… plain_wrapper

- Add ZEND_ASYNC_IO_SEEK API (typedef, extern, macro) for syncing libuv
  file offset after fseek/rewind in plain_wrapper
- Add ZEND_ASYNC_IO_APPEND flag (1 << 4) for correct append-mode offset
  initialization in async IO backends
- Update zend_async_io_register signature to accept seek_fn parameter
- Fix async IO exception handling in php_stdiop_read/php_stdiop_write:
  catch both EG(exception) and req->exception, clear them, emit E_NOTICE
  instead of propagating fatal exceptions from async IO errors
- Call ZEND_ASYNC_IO_SEEK from php_stdiop_seek for both fd and FILE* paths
- Set ZEND_ASYNC_IO_APPEND in php_stdiop_mode_to_io_state for 'a' mode
…stream in async context

- Add poll_event support for stdio/pipe streams on Linux via
  ZEND_ASYNC_NEW_POLL_EVENT, enabling stream_select() in async context.
  Windows returns NOTIMPL and falls back to regular select().
- Graceful fallback in stream_select(): when a stream does not support
  async poll, fall through to the regular select() path instead of
  throwing an error.
- Fix stream_copy_to_stream double-counting: sync async IO positions
  after copy_file_range() so the fallback read/write path sees the
  correct file offset.
- Add missing zend_exceptions.h include in plain_wrapper.c.
…stream in async context

- Add poll_event support for stdio/pipe streams on Linux via
  ZEND_ASYNC_NEW_POLL_EVENT, enabling stream_select() in async context.
  Windows returns NOTIMPL and falls back to regular select().
- Graceful fallback in stream_select(): when a stream does not support
  async poll, fall through to the regular select() path instead of
  throwing an error.
- Fix stream_copy_to_stream double-counting: sync async IO positions
  after copy_file_range() so the fallback read/write path sees the
  correct file offset.
- Add missing zend_exceptions.h include in plain_wrapper.c.
…stream in async context

- Add poll_event support for stdio/pipe streams on Linux via
  ZEND_ASYNC_NEW_POLL_EVENT, enabling stream_select() in async context.
  Windows returns NOTIMPL and falls back to regular select().
- Graceful fallback in stream_select(): when a stream does not support
  async poll, fall through to the regular select() path instead of
  throwing an error.
- Fix stream_copy_to_stream double-counting: add PHP_STREAM_OPTION_ALIGN_POSITION
  stream option to sync async IO internal position after copy_file_range()
  moves fd offsets directly.
- Add missing zend_exceptions.h include in plain_wrapper.c.
@EdmondDantes EdmondDantes requested a review from bukka as a code owner February 9, 2026 18:01
@EdmondDantes EdmondDantes merged commit 6594f06 into true-async-stable Feb 9, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant