Skip to content

Replace Events polling with notifications#389

Draft
realFlowControl wants to merge 8 commits into
developfrom
florian/notification-driven-events
Draft

Replace Events polling with notifications#389
realFlowControl wants to merge 8 commits into
developfrom
florian/notification-driven-events

Conversation

@realFlowControl

@realFlowControl realFlowControl commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Events::poll() now scans all watched targets once, then sleeps on a process-wide notification condition until a channel or future changes state. This replaces repeated random probing while keeping the public API unchanged; Windows x86 retains polling because pthreads-win32 condition waits hang there.

Why: idle polling previously spent about 0.47 CPU-seconds per wall-clock second. The notification-driven implementation reduced that to about 0.01 CPU-seconds, while median wake latency remained about 1.26 ms for 1, 10, and 1,000 targets (including a 1 ms producer delay).

What changed

  • Added a global notification epoch and condition variable; the epoch prevents missed wake-ups between scanning and sleeping.
  • Notify on channel readability/writability/close transitions and future terminal state changes.
  • Scan every target from a randomized offset for fairness instead of repeatedly sampling one target.
  • Stop immediately when no logical targets remain, including hash tables that retain empty backing buckets.
  • Use Zend’s monotonic clock on PHP 8.3+ with platform fallbacks for older PHP, translate Windows waits with pthreads-win32’s native deadline helper, and retain custom blocker behavior.
  • Retain a minimal polling fallback on Windows x86, where pthreads-win32 condition waits hang.
  • Added bounded stress coverage for channel/future wake-ups, 1,000 targets, blocker timeouts, and a timeout crossing one second.

Verification

  • Full suite: 148/148 tests pass.
  • PHP 8.0 event suite: 21/21 tests pass.
  • Notification stress test: 100/100 repeated runs pass.
  • CI: Linux, ASAN, UBSAN, clang-format, Coveralls, and Windows x64/x86 pass.

@krakjoe

krakjoe commented Jul 15, 2026

Copy link
Copy Markdown
Owner

This isn't really an acceptable approach, it has consequences for those not using the events api - we can't really lock a global mutex for link operations, it will introduce too much contention and even users not using the events api pay the significant price.

I have an idea for an alternative approach I've been mulling over for a while that might allow us to simply remove the events API, in favour of being able to use stream_select (or any other events API available).

It's possible to use the pipe() api to create anonymous pipes owned by a channel, thus raising events is just a write(), possibly conditionally, we can wrap the read end in a normal php stream, and so it can be used by stream_select.

here's a demo showing the kind of thing I mean ...

https://ideone.com/RQUZAk

As usual, I have no idea how to do this on windows ... there are limits on file descriptors that we would have to manage (only creating pipes for channels which we create a stream for, and with some limit/guardrails that make sense). I don't know the shape of the thing overall, just the basis I wanted to work from when I came to revisit this, and it does need revisiting, events are terrible.

Eventually I will get around to this, but it looks like you have the appetite right now :)

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.

2 participants