Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
61b683d
Add initial poll API
bukka Aug 15, 2025
9f5e16e
Add poll mechanism build checks and fix build
bukka Aug 16, 2025
c064161
Fix port and select backend and improve config
bukka Aug 16, 2025
ba5fe62
poll: restructure and refactore error handling and other bits
bukka Aug 16, 2025
7f6b60f
poll: use zend memory allocator
bukka Aug 16, 2025
a8ba8d9
poll: split init from create
bukka Aug 16, 2025
cecbe24
poll: use pefree instead of free everywhere
bukka Aug 16, 2025
ab65c4b
poll: declare PHPAPI
bukka Aug 16, 2025
d49d26e
poll: fix kqueue build
bukka Aug 18, 2025
4ef72ac
Add initial streams polling API
bukka Aug 19, 2025
69e8ef8
poll: add missing private constructor
bukka Aug 19, 2025
cb1ff80
poll: add initial test
bukka Aug 19, 2025
c26d075
poll: reorganize stubs so functions are added
bukka Aug 19, 2025
176fabf
poll: do not dtor stream event property
bukka Aug 20, 2025
3213558
poll: split the basic test to multiple eparated scenarios
bukka Aug 20, 2025
8b7dd93
poll: fix returned events
bukka Aug 20, 2025
f89edd4
poll: rewrite kevent to track changed events
bukka Aug 20, 2025
6e32aaa
poll: refactore kevent to get rid of long term batching
bukka Aug 20, 2025
35d8081
poll: add modify and write test
bukka Aug 20, 2025
5599127
poll: optimize and refactore all apis to better handle max_events
bukka Aug 21, 2025
6e46309
poll: use common logic for fd tracking
bukka Aug 21, 2025
2e3828a
poll: use custom allocation macros that can fail on persistent
bukka Aug 21, 2025
0c1a478
poll: add Windows build config changes
bukka Aug 21, 2025
4f4cf8a
poll: support poll creation by backend name
bukka Aug 21, 2025
cf4cf28
poll: clean up and update tests to allow backend selection
bukka Aug 21, 2025
1d1f38a
poll: refactore, simplify and extend tests
bukka Aug 21, 2025
def2ddb
poll: fix kqueue removal logic
bukka Aug 22, 2025
4638073
poll: check stream map before deleting for better error
bukka Aug 22, 2025
b5f0068
poll: extend and simplify tests
bukka Aug 22, 2025
74d6835
poll: add suitable max events callback to get right number of events …
bukka Aug 22, 2025
c692858
poll: group kqueue events and correctly count max events
bukka Aug 22, 2025
e3b2ad9
poll: make the kqueue one shot logic consistent with epoll
bukka Aug 22, 2025
cd3bece
poll: refactore and simplify oneshot kqueue logic
bukka Aug 23, 2025
8baf70d
poll: improve and extend error handling with some helpers
bukka Aug 23, 2025
d15bfdc
poll: extend and clean up tests
bukka Aug 23, 2025
d968e22
poll: rewrite tests to expect events in any order
bukka Aug 23, 2025
9023136
poll: support backend specific events in event expectation
bukka Aug 23, 2025
e6946e6
poll: extend and fix edge tests
bukka Aug 23, 2025
35810ab
poll: refactore and optimize fd table
bukka Aug 23, 2025
d067e29
poll: refactore poll logic to use more optimally fd table
bukka Aug 23, 2025
5f85e9f
poll: remove incorrect edge triggering simulation
bukka Aug 23, 2025
cc67857
poll: fix test reporting of unpexpected events when array present
bukka Aug 24, 2025
2dfdacd
poll: fix, refactore and simplify poll backend
bukka Aug 24, 2025
8ad812b
Make poll always available
bukka Aug 24, 2025
6509749
poll: remove select backend as it is broken and not needed
bukka Aug 24, 2025
7d770b7
poll: fix compilation issues
bukka Aug 24, 2025
b075ab4
poll: use STREAM_POLL_WRITE|STREAM_POLL_HUP as default for HOP
bukka Aug 24, 2025
248f2bb
poll: use php_pollfd instead of struct pollfd
bukka Aug 24, 2025
9148b77
poll: remove select backend constants and fix backend name test
bukka Aug 24, 2025
4331731
poll: add stream poll classes to reflection getClassName test
bukka Aug 24, 2025
8799d67
poll: update arginfo
bukka Aug 24, 2025
1201131
poll: introduce php_poll_msleep for win compat
bukka Aug 24, 2025
19890fc
Drop IOCP backend as it is not suitable
bukka Sep 19, 2025
c46226a
poll: add wsapoll backend with additional tests and fix Win compat
bukka Sep 21, 2025
d57b4c0
poll: fix wsapoll CS
bukka Sep 21, 2025
c0135be
poll: fix wsapoll and poll compatibility
bukka Sep 21, 2025
0deb18e
poll: add raw events support to allow lower overhead on kqueue
bukka Sep 22, 2025
c1ddfc0
poll: add actually kqueue implementation for raw_events
bukka Sep 22, 2025
d4740ed
poll: add initial obj migration
bukka Sep 23, 2025
68958b5
poll: add primary implementation and tests for objective polling
bukka Sep 24, 2025
f4ef694
poll: fix failed addition
bukka Sep 24, 2025
7d90473
poll: fix poll testing helpers
bukka Sep 24, 2025
4edefc1
poll: fix missing stream addref or return from getStream
bukka Sep 24, 2025
ebf7e23
poll: fix raw event check
bukka Sep 24, 2025
50e5254
poll: drop compat flag as it does not make sense for watchers
bukka Sep 24, 2025
25ad206
poll: remove unused compat variable
bukka Sep 24, 2025
dd4c021
poll: update classes in ReflectionExtension::getClassNames
bukka Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
poll: remove incorrect edge triggering simulation
  • Loading branch information
bukka committed Sep 24, 2025
commit 5f85e9fe10be2eb5e40cc58ba4c60091fc02fefb
19 changes: 14 additions & 5 deletions ext/standard/tests/streams/stream_poll.inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
<?php
// stream Poll Testing helper

function pt_new_stream_poll(): StreamPollContext {
$backend = getenv('STREAM_POLL_TEST_BACKEND');
return stream_poll_create($backend === false ? STREAM_POLL_BACKEND_AUTO : $backend);
}

function pt_skip_for_backend($backend, $msg): void {
$backends_to_skip = is_array($backend) ? $backend : array($backend);
$current_backend = stream_poll_backend_name(pt_new_stream_poll());
if (in_array($current_backend, $backends_to_skip)) {
die("skip backend $current_backend $msg\n");
}
}

function pt_new_socket_pair(): array {
$domain = (strtoupper(substr(PHP_OS, 0, 3) == 'WIN') ? STREAM_PF_INET : STREAM_PF_UNIX);
$sockets = stream_socket_pair($domain, STREAM_SOCK_STREAM, 0);
Expand Down Expand Up @@ -65,11 +79,6 @@ function pt_new_tcp_socket_connections(int $num_conns): array {
return [$clients, $server_conns];
}

function pt_new_stream_poll(): StreamPollContext {
$backend = getenv('STREAM_POLL_TEST_BACKEND');
return stream_poll_create($backend === false ? STREAM_POLL_BACKEND_AUTO : $backend);
}

function pt_write_sleep($stream, $data, $delay = 10000): int|false {
$result = fwrite($stream, $data, $delay);
usleep($delay);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
--TEST--
Stream polling - socket write / read multiple times with edge triggering
--SKIPIF--
<?php
require_once __DIR__ . '/stream_poll.inc';
pt_skip_for_backend(['poll', 'select'], 'does not support edger triggering')
?>
--FILE--
<?php
require_once __DIR__ . '/stream_poll.inc';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ pt_expect_events(stream_poll_wait($poll_ctx, 100), [
?>
--EXPECT--
Events matched - count: 1
Events matched - count: 2
Events matched - count: 1
3 changes: 0 additions & 3 deletions main/poll/php_poll_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@ php_socket_t php_poll_fd_table_get_max_fd(php_poll_fd_table *table);
int php_poll_fd_table_collect_events(
php_poll_fd_table *table, php_poll_event *events, int max_events);

/* Edge triggering simulation helper */
int php_poll_simulate_edge_trigger(php_poll_fd_table *table, php_poll_event *events, int nfds);

/* Error helper functions */
php_poll_error php_poll_errno_to_error(int err);

Expand Down
13 changes: 10 additions & 3 deletions main/poll/poll_backend_poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ static zend_result poll_backend_add(php_poll_ctx *ctx, int fd, uint32_t events,
{
poll_backend_data_t *backend_data = (poll_backend_data_t *) ctx->backend_data;

if (events & PHP_POLL_ET) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOSUPPORT);
return FAILURE;
}

if (php_poll_fd_table_find(backend_data->fd_table, fd)) {
php_poll_set_error(ctx, PHP_POLL_ERR_EXISTS);
return FAILURE;
Expand All @@ -130,6 +135,11 @@ static zend_result poll_backend_modify(php_poll_ctx *ctx, int fd, uint32_t event
{
poll_backend_data_t *backend_data = (poll_backend_data_t *) ctx->backend_data;

if (events & PHP_POLL_ET) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOSUPPORT);
return FAILURE;
}

php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, fd);
if (!entry) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOTFOUND);
Expand Down Expand Up @@ -256,9 +266,6 @@ static int poll_backend_wait(php_poll_ctx *ctx, php_poll_event *events, int max_
backend_data->fd_table, poll_process_results_callback, &result_ctx);
int event_count = result_ctx.event_count;

/* Apply edge-trigger simulation */
nfds = php_poll_simulate_edge_trigger(backend_data->fd_table, events, event_count);

/* Handle oneshot removals */
for (int i = 0; i < nfds; i++) {
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, events[i].fd);
Expand Down
17 changes: 12 additions & 5 deletions main/poll/poll_backend_select.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ static zend_result select_backend_add(php_poll_ctx *ctx, int fd, uint32_t events
select_backend_data_t *backend_data = (select_backend_data_t *) ctx->backend_data;
php_socket_t sock = (php_socket_t) fd;

if (events & PHP_POLL_ET) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOSUPPORT);
return FAILURE;
}

#ifdef FD_SETSIZE
if (sock >= FD_SETSIZE) {
php_poll_set_error(ctx, PHP_POLL_ERR_INVALID);
Expand Down Expand Up @@ -139,6 +144,11 @@ static zend_result select_backend_modify(
select_backend_data_t *backend_data = (select_backend_data_t *) ctx->backend_data;
php_socket_t sock = (php_socket_t) fd;

if (events & PHP_POLL_ET) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOSUPPORT);
return FAILURE;
}

php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, fd);
if (!entry) {
php_poll_set_error(ctx, PHP_POLL_ERR_NOTFOUND);
Expand Down Expand Up @@ -293,18 +303,15 @@ static int select_backend_wait(
php_poll_fd_table_foreach(backend_data->fd_table, process_select_result_callback, &result_ctx);
int event_count = result_ctx.event_count;

/* Apply edge-trigger simulation */
int nfds = php_poll_simulate_edge_trigger(backend_data->fd_table, events, event_count);

/* Handle oneshot removals */
for (int i = 0; i < nfds; i++) {
for (int i = 0; i < event_count; i++) {
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, events[i].fd);
if (entry && (entry->events & PHP_POLL_ONESHOT) && events[i].revents != 0) {
select_handle_oneshot_removal(backend_data, events[i].fd);
}
}

return nfds;
return event_count;
}

static bool select_backend_is_available(void)
Expand Down
44 changes: 0 additions & 44 deletions main/poll/poll_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,47 +406,3 @@ PHPAPI const char *php_poll_error_string(php_poll_error error)
return "Unknown error";
}
}

/* Edge-trigger simulation helper */
int php_poll_simulate_edge_trigger(php_poll_fd_table *table, php_poll_event *events, int nfds)
{
int filtered_count = 0;

for (int i = 0; i < nfds; i++) {
php_poll_fd_entry *entry = php_poll_fd_table_find(table, events[i].fd);
if (!entry) {
continue;
}

uint32_t new_events = events[i].revents;
uint32_t reported_events = 0;

if (entry->events & PHP_POLL_ET) {
/* Edge-triggered: report edges only */
if ((new_events & PHP_POLL_READ) && !(entry->last_revents & PHP_POLL_READ)) {
reported_events |= PHP_POLL_READ;
}
if ((new_events & PHP_POLL_WRITE) && !(entry->last_revents & PHP_POLL_WRITE)) {
reported_events |= PHP_POLL_WRITE;
}
/* Always report error and hangup events */
reported_events |= (new_events & (PHP_POLL_ERROR | PHP_POLL_HUP | PHP_POLL_RDHUP));
} else {
/* Level-triggered: report all active events */
reported_events = new_events;
}

entry->last_revents = new_events;

/* Only include this event if we have something to report */
if (reported_events != 0) {
if (filtered_count != i) {
events[filtered_count] = events[i];
}
events[filtered_count].revents = reported_events;
filtered_count++;
}
}

return filtered_count;
}