Re: [RFC] Polling API Additions
| From: | Ilia | Date: | Thu, 01 Oct 2026 16:14:08 +0000 |
| Subject: | Re: [RFC] Polling API Additions | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-132757@lists.php.net to get a copy of this message | ||
On Wed, Sep 30, 2026 at 2:00 PM Jakub Zelenka <bukka@php.net> 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: ilia@ilia.ws
T: @iliaa
B: http://ilia.ws