Skip to content

Commit c57a8f7

Browse files
committed
poll: fix, refactore and simplify poll backend
1 parent dce3480 commit c57a8f7

File tree

4 files changed

+42
-57
lines changed

4 files changed

+42
-57
lines changed

ext/standard/tests/streams/stream_poll.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ function pt_event_flags_to_string($flags): string {
227227
if ($flags & STREAM_POLL_ERROR) $names[] = 'ERROR';
228228
if ($flags & STREAM_POLL_HUP) $names[] = 'HUP';
229229

230-
return empty($names) ? 'NONE' : implode('|', $names);
230+
return empty($names) ? 'NONE:' . $flags : implode('|', $names);
231231
}
232232

233233
function pt_print_mismatched_events($actual_events, $expected_events, $matched = [], $backend_name = null): void {

ext/standard/tests/streams/stream_poll_basic_sock_rw_multi_edge.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Stream polling - socket write / read multiple times with edge triggering
33
--SKIPIF--
44
<?php
55
require_once __DIR__ . '/stream_poll.inc';
6-
pt_skip_for_backend(['poll', 'select'], 'does not support edger triggering')
6+
pt_skip_for_backend(['poll', 'select'], 'does not support edge triggering')
77
?>
88
--FILE--
99
<?php

ext/standard/tests/streams/stream_poll_basic_sock_rw_single_edge.phpt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
--TEST--
22
Stream polling - socket write / read few time only
3+
--SKIPIF--
4+
<?php
5+
require_once __DIR__ . '/stream_poll.inc';
6+
pt_skip_for_backend(['poll', 'select'], 'does not support edge triggering')
7+
?>
38
--FILE--
49
<?php
510
require_once __DIR__ . '/stream_poll.inc';

main/poll/poll_backend_poll.c

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
typedef struct {
2424
php_poll_fd_table *fd_table;
25-
/* Temporary arrays allocated during poll_backend_wait() */
2625
struct pollfd *temp_fds;
2726
int temp_fds_capacity;
2827
} poll_backend_data_t;
@@ -60,6 +59,9 @@ static uint32_t poll_events_from_native(uint32_t native)
6059
if (native & POLLHUP) {
6160
events |= PHP_POLL_HUP;
6261
}
62+
if (native & POLLNVAL) {
63+
events |= PHP_POLL_ERROR; /* Map invalid FD to error */
64+
}
6365
return events;
6466
}
6567

@@ -80,7 +82,6 @@ static zend_result poll_backend_init(php_poll_ctx *ctx)
8082
return FAILURE;
8183
}
8284

83-
/* Pre-allocate temporary pollfd array */
8485
data->temp_fds = php_poll_calloc(initial_capacity, sizeof(struct pollfd), ctx->persistent);
8586
if (!data->temp_fds) {
8687
php_poll_fd_table_cleanup(data->fd_table);
@@ -148,7 +149,6 @@ static zend_result poll_backend_modify(php_poll_ctx *ctx, int fd, uint32_t event
148149

149150
entry->events = events;
150151
entry->data = user_data;
151-
entry->last_revents = 0;
152152

153153
return SUCCESS;
154154
}
@@ -186,40 +186,6 @@ static bool poll_build_fds_callback(int fd, php_poll_fd_entry *entry, void *user
186186
return true;
187187
}
188188

189-
/* Context for processing poll results */
190-
typedef struct {
191-
poll_backend_data_t *backend_data;
192-
struct pollfd *pollfds;
193-
php_poll_event *events;
194-
int max_events;
195-
int event_count;
196-
} poll_result_context;
197-
198-
/* Callback to process poll results */
199-
static bool poll_process_results_callback(int fd, php_poll_fd_entry *entry, void *user_data)
200-
{
201-
poll_result_context *ctx = (poll_result_context *) user_data;
202-
203-
if (ctx->event_count >= ctx->max_events) {
204-
return false; /* Stop if events array is full */
205-
}
206-
207-
/* Find the corresponding pollfd entry */
208-
for (int i = 0; i < php_poll_fd_table_count(ctx->backend_data->fd_table); i++) {
209-
if (ctx->pollfds[i].fd == fd && ctx->pollfds[i].revents != 0) {
210-
ctx->events[ctx->event_count].fd = fd;
211-
ctx->events[ctx->event_count].events = entry->events;
212-
ctx->events[ctx->event_count].revents
213-
= poll_events_from_native(ctx->pollfds[i].revents);
214-
ctx->events[ctx->event_count].data = entry->data;
215-
ctx->event_count++;
216-
break;
217-
}
218-
}
219-
220-
return true;
221-
}
222-
223189
static int poll_backend_wait(php_poll_ctx *ctx, php_poll_event *events, int max_events, int timeout)
224190
{
225191
poll_backend_data_t *backend_data = (poll_backend_data_t *) ctx->backend_data;
@@ -254,28 +220,42 @@ static int poll_backend_wait(php_poll_ctx *ctx, php_poll_event *events, int max_
254220
/* Call poll() */
255221
int nfds = poll(backend_data->temp_fds, fd_count, timeout);
256222

257-
if (nfds > 0) {
258-
/* Process results */
259-
poll_result_context result_ctx = { .backend_data = backend_data,
260-
.pollfds = backend_data->temp_fds,
261-
.events = events,
262-
.max_events = max_events,
263-
.event_count = 0 };
264-
265-
php_poll_fd_table_foreach(
266-
backend_data->fd_table, poll_process_results_callback, &result_ctx);
267-
int event_count = result_ctx.event_count;
268-
269-
/* Handle oneshot removals */
270-
for (int i = 0; i < nfds; i++) {
271-
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, events[i].fd);
272-
if (entry && (entry->events & PHP_POLL_ONESHOT) && events[i].revents != 0) {
273-
php_poll_fd_table_remove(backend_data->fd_table, events[i].fd);
223+
if (nfds <= 0) {
224+
return nfds; /* Return 0 for timeout, -1 for error */
225+
}
226+
227+
/* Process results - iterate through pollfd array directly */
228+
int event_count = 0;
229+
for (int i = 0; i < fd_count && event_count < max_events; i++) {
230+
struct pollfd *pfd = &backend_data->temp_fds[i];
231+
232+
if (pfd->revents != 0) {
233+
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, pfd->fd);
234+
if (entry) {
235+
/* Handle POLLNVAL by automatically removing the invalid FD */
236+
if (pfd->revents & POLLNVAL) {
237+
php_poll_fd_table_remove(backend_data->fd_table, pfd->fd);
238+
continue; /* Don't report this event */
239+
}
240+
241+
events[event_count].fd = pfd->fd;
242+
events[event_count].events = entry->events;
243+
events[event_count].revents = poll_events_from_native(pfd->revents);
244+
events[event_count].data = entry->data;
245+
event_count++;
274246
}
275247
}
276248
}
277249

278-
return nfds;
250+
/* Handle oneshot removals */
251+
for (int i = 0; i < event_count; i++) {
252+
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, events[i].fd);
253+
if (entry && (entry->events & PHP_POLL_ONESHOT) && events[i].revents != 0) {
254+
php_poll_fd_table_remove(backend_data->fd_table, events[i].fd);
255+
}
256+
}
257+
258+
return event_count;
279259
}
280260

281261
static bool poll_backend_is_available(void)

0 commit comments

Comments
 (0)