Skip to content

Commit e168f07

Browse files
committed
poll: add handling for eventport unfired events
1 parent 6ae469c commit e168f07

File tree

1 file changed

+78
-40
lines changed

1 file changed

+78
-40
lines changed

main/poll/poll_backend_eventport.c

Lines changed: 78 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <stdlib.h>
2222
#include <string.h>
2323
#include <errno.h>
24+
#include <poll.h>
2425

2526
typedef struct {
2627
int port_fd;
@@ -245,39 +246,6 @@ static zend_result eventport_backend_remove(php_poll_ctx *ctx, int fd)
245246
return SUCCESS;
246247
}
247248

248-
/* Handle re-association after event */
249-
static void eventport_handle_reassociation(
250-
eventport_backend_data_t *backend_data, int fd, uint32_t fired_events)
251-
{
252-
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, fd);
253-
if (!entry) {
254-
return;
255-
}
256-
257-
if (entry->events & PHP_POLL_ONESHOT) {
258-
/* Oneshot: remove from tracking */
259-
php_poll_fd_table_remove(backend_data->fd_table, fd);
260-
backend_data->active_associations--;
261-
return;
262-
}
263-
264-
/* Re-associate for continued monitoring */
265-
int native_events = eventport_events_to_native(entry->events);
266-
if (native_events == 0) {
267-
/* Nothing meaningful to watch - stop tracking */
268-
php_poll_fd_table_remove(backend_data->fd_table, fd);
269-
backend_data->active_associations--;
270-
return;
271-
}
272-
273-
if (port_associate(backend_data->port_fd, PORT_SOURCE_FD, fd, native_events, entry->data)
274-
!= 0) {
275-
/* Re-association failed - might be due to fd being closed */
276-
php_poll_fd_table_remove(backend_data->fd_table, fd);
277-
backend_data->active_associations--;
278-
}
279-
}
280-
281249
/* Wait for events using event port */
282250
static int eventport_backend_wait(
283251
php_poll_ctx *ctx, php_poll_event *events, int max_events, int timeout)
@@ -321,24 +289,55 @@ static int eventport_backend_wait(
321289

322290
if (result == -1) {
323291
php_poll_set_current_errno_error(ctx);
292+
return -1;
324293
}
325294

326295
int nfds = (int) nget;
296+
int check_count = 0;
327297

328-
/* Process the events and handle re-association */
298+
/* First pass: process events, identify unfired events, and re-associate */
329299
for (int i = 0; i < nfds; i++) {
330300
port_event_t *port_event = &backend_data->events[i];
331301

332302
/* Only handle PORT_SOURCE_FD events */
333303
if (port_event->portev_source == PORT_SOURCE_FD) {
334304
int fd = (int) port_event->portev_object;
305+
uint32_t fired = eventport_events_from_native(port_event->portev_events);
306+
335307
events[i].fd = fd;
336-
events[i].events = 0; /* Not used in results */
337-
events[i].revents = eventport_events_from_native(port_event->portev_events);
308+
events[i].events = 0;
309+
events[i].revents = fired;
338310
events[i].data = port_event->portev_user;
339311

340-
/* Handle re-association based on event type */
341-
eventport_handle_reassociation(backend_data, fd, events[i].revents);
312+
/* Get entry and handle re-association */
313+
php_poll_fd_entry *entry = php_poll_fd_table_find(backend_data->fd_table, fd);
314+
if (entry) {
315+
if (entry->events & PHP_POLL_ONESHOT) {
316+
/* Oneshot: remove from tracking */
317+
php_poll_fd_table_remove(backend_data->fd_table, fd);
318+
backend_data->active_associations--;
319+
} else {
320+
/* Check if there are other events we're monitoring */
321+
uint32_t monitored = entry->events & (PHP_POLL_READ | PHP_POLL_WRITE);
322+
uint32_t unfired = monitored & ~fired;
323+
324+
if (unfired) {
325+
/* Store unfired events for potential second-round check */
326+
events[i].events = unfired;
327+
check_count++;
328+
}
329+
330+
/* Re-associate immediately with all originally registered events */
331+
int native_events = eventport_events_to_native(entry->events);
332+
if (port_associate(backend_data->port_fd, PORT_SOURCE_FD, fd, native_events,
333+
entry->data)
334+
!= 0) {
335+
/* Re-association failed - remove from tracking */
336+
php_poll_fd_table_remove(backend_data->fd_table, fd);
337+
backend_data->active_associations--;
338+
}
339+
}
340+
}
342341
} else {
343342
/* Handle other event sources if needed (timers, user events, etc.) */
344343
events[i].fd = -1;
@@ -348,6 +347,46 @@ static int eventport_backend_wait(
348347
}
349348
}
350349

350+
/* Second pass: if we have unfired events, check them with poll() */
351+
if (check_count > 0) {
352+
struct pollfd *check_fds
353+
= php_poll_calloc(check_count, sizeof(struct pollfd), ctx->persistent);
354+
int *check_indices = php_poll_calloc(check_count, sizeof(int), ctx->persistent);
355+
356+
if (check_fds && check_indices) {
357+
int check_idx = 0;
358+
for (int i = 0; i < nfds; i++) {
359+
if (events[i].events != 0 && events[i].fd >= 0) {
360+
check_fds[check_idx].fd = events[i].fd;
361+
check_fds[check_idx].events = eventport_events_to_native(events[i].events);
362+
check_fds[check_idx].revents = 0;
363+
check_indices[check_idx] = i;
364+
check_idx++;
365+
events[i].events = 0; /* Clear it as it was just temporary */
366+
}
367+
}
368+
369+
/* Non-blocking poll to check if other events are ready */
370+
if (poll(check_fds, check_count, 0) > 0) {
371+
for (int j = 0; j < check_count; j++) {
372+
if (check_fds[j].revents != 0) {
373+
int evt_idx = check_indices[j];
374+
uint32_t additional = eventport_events_from_native(check_fds[j].revents);
375+
/* Add the additional ready events to revents */
376+
events[evt_idx].revents |= additional;
377+
}
378+
}
379+
}
380+
}
381+
382+
if (check_fds) {
383+
pefree(check_fds, ctx->persistent);
384+
}
385+
if (check_indices) {
386+
pefree(check_indices, ctx->persistent);
387+
}
388+
}
389+
351390
return nfds;
352391
}
353392

@@ -394,8 +433,7 @@ const php_poll_backend_ops php_poll_backend_eventport_ops = {
394433
.wait = eventport_backend_wait,
395434
.is_available = eventport_backend_is_available,
396435
.get_suitable_max_events = eventport_backend_get_suitable_max_events,
397-
.supports_et = false
436+
.supports_et = false /* Event ports are level-triggered only */
398437
};
399438

400439
#endif /* HAVE_EVENT_PORTS */
401-

0 commit comments

Comments
 (0)