On Wed, Sep 30, 2026 at 2:00 PM Jakub Zelenka <[email protected]> wrote:

> I would like to introduce the Polling API Additions RFC:
>
> https://wiki.php.net/rfc/poll_api_additions
>

Hi Jakub,

Timers, notify and priority look good to me, and the deadline heap and
WNOWAIT choices are the right ones. A few things from reading and
running the io_hooks_poc branch before a vote:

1. Please split the vote by group. Signals carry most of the risk and
   shouldn't hold back timers.

2. exec(), system(), passthru(), shell_exec() and backticks go through
   libc popen() and never reset the mask. With /bin/sh as bash the
   child gets SIGTERM blocked; with dash only exec-prefixed commands
   do. "The blocked mask does not leak into executed programs" needs a
   single choke point, not a list of call sites.

3. pcntl can unblock a watched signal behind the handle:
   pcntl_sigprocmask(SIG_UNBLOCK/SIG_SETMASK) directly, and
   pcntl_signal() via zend_sigaction(), which unblocks the signal it
   installs. In both cases the pcntl handler runs and the handle sees
   nothing, so "a handler installed with pcntl_signal() never runs
   while a handle for it is watched" doesn't hold with zend signals on.

4. While SIGTERM is watched, sleep() and blocking reads run to
   completion, and a script that never calls wait() exits 0: the
   shutdown drain records the signal into a handle that is then freed.
   Worth stating, and it's the main argument for the self-pipe model
   in your open issue.

5. onWatcherRemoved also fires for the script's own fclose() (your
   poll_weakhandle_on_watcher_removed.phpt relies on it), so the
   connection-table example comment is wrong.

6. The PoC changes wait() on EINTR from throwing FailedPollWaitException
   to restarting or returning []. I think that's right, but it changes
   the 8.6 API and should be in the RFC. A signal landing in wait()
   before the syscall still blocks it with the PHP handler pending; a
   php_io_interrupt_pending() check before blocking would close that.

7. ProcessHandle: new ProcessHandle($pid) for a non-child races pid
   reuse, and the exit probe uses waitid(P_PID) rather than P_PIDFD, so
   after an external reap it can read another process's status.
   getStatus() is a wait status on POSIX and an exit code on Windows,
   and non-null for non-children only on Windows.

8. TimerHandle: please specify the clock and that the deadline starts
   at add(), which is what the PoC does with zend_hrtime().

9. isExposed() and the in-use null from getStream() can't be observed
   through this RFC's API alone; they belong with IO hooks.

-- 
Ilia Alshanetsky
Technologist, CTO, Entrepreneur
E: [email protected]
T: @iliaa
B: http://ilia.ws

Reply via email to