21
21
#include <string.h>
22
22
23
23
typedef struct {
24
- struct pollfd * fds ;
25
- int fds_capacity ;
26
- int fds_used ;
27
24
php_poll_fd_table * fd_table ;
25
+ /* Temporary arrays allocated during poll_backend_wait() */
26
+ struct pollfd * temp_fds ;
27
+ int temp_fds_capacity ;
28
28
} poll_backend_data_t ;
29
29
30
30
static uint32_t poll_events_to_native (uint32_t events )
@@ -63,28 +63,6 @@ static uint32_t poll_events_from_native(uint32_t native)
63
63
return events ;
64
64
}
65
65
66
- /* Find pollfd slot */
67
- static struct pollfd * poll_find_pollfd_slot (poll_backend_data_t * data , int fd )
68
- {
69
- for (int i = 0 ; i < data -> fds_capacity ; i ++ ) {
70
- if (data -> fds [i ].fd == fd ) {
71
- return & data -> fds [i ];
72
- }
73
- }
74
- return NULL ;
75
- }
76
-
77
- /* Get empty pollfd slot */
78
- static struct pollfd * poll_get_empty_pollfd_slot (poll_backend_data_t * data )
79
- {
80
- for (int i = 0 ; i < data -> fds_capacity ; i ++ ) {
81
- if (data -> fds [i ].fd == -1 ) {
82
- return & data -> fds [i ];
83
- }
84
- }
85
- return NULL ;
86
- }
87
-
88
66
static zend_result poll_backend_init (php_poll_ctx * ctx )
89
67
{
90
68
poll_backend_data_t * data = php_poll_calloc (1 , sizeof (poll_backend_data_t ), ctx -> persistent );
@@ -93,30 +71,24 @@ static zend_result poll_backend_init(php_poll_ctx *ctx)
93
71
return FAILURE ;
94
72
}
95
73
96
- /* Use hint for initial allocation if provided, otherwise start with reasonable default */
97
74
int initial_capacity = ctx -> max_events_hint > 0 ? ctx -> max_events_hint : 64 ;
98
75
99
- data -> fds = php_poll_calloc (initial_capacity , sizeof ( struct pollfd ) , ctx -> persistent );
100
- if (!data -> fds ) {
76
+ data -> fd_table = php_poll_fd_table_init (initial_capacity , ctx -> persistent );
77
+ if (!data -> fd_table ) {
101
78
pefree (data , ctx -> persistent );
102
79
php_poll_set_error (ctx , PHP_POLL_ERR_NOMEM );
103
80
return FAILURE ;
104
81
}
105
- data -> fds_capacity = initial_capacity ;
106
- data -> fds_used = 0 ;
107
82
108
- data -> fd_table = php_poll_fd_table_init (initial_capacity , ctx -> persistent );
109
- if (!data -> fd_table ) {
110
- pefree (data -> fds , ctx -> persistent );
83
+ /* Pre-allocate temporary pollfd array */
84
+ data -> temp_fds = php_poll_calloc (initial_capacity , sizeof (struct pollfd ), ctx -> persistent );
85
+ if (!data -> temp_fds ) {
86
+ php_poll_fd_table_cleanup (data -> fd_table );
111
87
pefree (data , ctx -> persistent );
112
88
php_poll_set_error (ctx , PHP_POLL_ERR_NOMEM );
113
89
return FAILURE ;
114
90
}
115
-
116
- /* Initialize all fds to -1 */
117
- for (int i = 0 ; i < initial_capacity ; i ++ ) {
118
- data -> fds [i ].fd = -1 ;
119
- }
91
+ data -> temp_fds_capacity = initial_capacity ;
120
92
121
93
ctx -> backend_data = data ;
122
94
return SUCCESS ;
@@ -126,8 +98,8 @@ static void poll_backend_cleanup(php_poll_ctx *ctx)
126
98
{
127
99
poll_backend_data_t * data = (poll_backend_data_t * ) ctx -> backend_data ;
128
100
if (data ) {
129
- pefree (data -> fds , ctx -> persistent );
130
101
php_poll_fd_table_cleanup (data -> fd_table );
102
+ pefree (data -> temp_fds , ctx -> persistent );
131
103
pefree (data , ctx -> persistent );
132
104
ctx -> backend_data = NULL ;
133
105
}
@@ -151,59 +123,22 @@ static zend_result poll_backend_add(php_poll_ctx *ctx, int fd, uint32_t events,
151
123
entry -> events = events ;
152
124
entry -> data = user_data ;
153
125
154
- /* Find empty pollfd slot */
155
- struct pollfd * pfd = poll_get_empty_pollfd_slot (backend_data );
156
- if (!pfd ) {
157
- /* Need to grow the pollfd array */
158
- int new_capacity = backend_data -> fds_capacity * 2 ;
159
- struct pollfd * new_fds = php_poll_realloc (
160
- backend_data -> fds , new_capacity * sizeof (struct pollfd ), ctx -> persistent );
161
- if (!new_fds ) {
162
- php_poll_fd_table_remove (backend_data -> fd_table , fd );
163
- php_poll_set_error (ctx , PHP_POLL_ERR_NOMEM );
164
- return FAILURE ;
165
- }
166
-
167
- /* Initialize new slots */
168
- for (int i = backend_data -> fds_capacity ; i < new_capacity ; i ++ ) {
169
- new_fds [i ].fd = -1 ;
170
- }
171
-
172
- backend_data -> fds = new_fds ;
173
- pfd = & backend_data -> fds [backend_data -> fds_capacity ];
174
- backend_data -> fds_capacity = new_capacity ;
175
- }
176
-
177
- /* Set up pollfd */
178
- pfd -> fd = fd ;
179
- pfd -> events = poll_events_to_native (events & ~(PHP_POLL_ET | PHP_POLL_ONESHOT ));
180
- pfd -> revents = 0 ;
181
- backend_data -> fds_used ++ ;
182
-
183
126
return SUCCESS ;
184
127
}
185
128
186
129
static zend_result poll_backend_modify (php_poll_ctx * ctx , int fd , uint32_t events , void * user_data )
187
130
{
188
131
poll_backend_data_t * backend_data = (poll_backend_data_t * ) ctx -> backend_data ;
189
132
190
- /* Find existing entry using helper - O(1) instead of O(n) */
191
133
php_poll_fd_entry * entry = php_poll_fd_table_find (backend_data -> fd_table , fd );
192
134
if (!entry ) {
193
135
php_poll_set_error (ctx , PHP_POLL_ERR_NOTFOUND );
194
136
return FAILURE ;
195
137
}
196
138
197
- /* Update entry */
198
139
entry -> events = events ;
199
140
entry -> data = user_data ;
200
- entry -> last_revents = 0 ; /* Reset on modify */
201
-
202
- /* Find pollfd and update */
203
- struct pollfd * pfd = poll_find_pollfd_slot (backend_data , fd );
204
- if (pfd ) {
205
- pfd -> events = poll_events_to_native (events & ~(PHP_POLL_ET | PHP_POLL_ONESHOT ));
206
- }
141
+ entry -> last_revents = 0 ;
207
142
208
143
return SUCCESS ;
209
144
}
@@ -217,40 +152,70 @@ static zend_result poll_backend_remove(php_poll_ctx *ctx, int fd)
217
152
return FAILURE ;
218
153
}
219
154
220
- /* Find and clear pollfd */
221
- struct pollfd * pfd = poll_find_pollfd_slot (backend_data , fd );
222
- if (pfd ) {
223
- pfd -> fd = -1 ;
224
- pfd -> events = 0 ;
225
- pfd -> revents = 0 ;
226
- backend_data -> fds_used -- ;
227
- }
228
-
229
155
php_poll_fd_table_remove (backend_data -> fd_table , fd );
230
-
231
156
return SUCCESS ;
232
157
}
233
158
234
- /* Handle oneshot removal after event */
235
- static void poll_handle_oneshot_removal (poll_backend_data_t * backend_data , int fd )
159
+ /* Context for building pollfd array */
160
+ typedef struct {
161
+ struct pollfd * fds ;
162
+ int index ;
163
+ } poll_build_context ;
164
+
165
+ /* Callback to build pollfd array from fd_table */
166
+ static bool poll_build_fds_callback (int fd , php_poll_fd_entry * entry , void * user_data )
236
167
{
237
- /* Mark pollfd as disabled */
238
- struct pollfd * pfd = poll_find_pollfd_slot (backend_data , fd );
239
- if (pfd ) {
240
- pfd -> fd = -1 ;
241
- pfd -> events = 0 ;
242
- pfd -> revents = 0 ;
243
- backend_data -> fds_used -- ;
168
+ poll_build_context * ctx = (poll_build_context * ) user_data ;
169
+
170
+ ctx -> fds [ctx -> index ].fd = fd ;
171
+ ctx -> fds [ctx -> index ].events
172
+ = poll_events_to_native (entry -> events & ~(PHP_POLL_ET | PHP_POLL_ONESHOT ));
173
+ ctx -> fds [ctx -> index ].revents = 0 ;
174
+ ctx -> index ++ ;
175
+
176
+ return true;
177
+ }
178
+
179
+ /* Context for processing poll results */
180
+ typedef struct {
181
+ poll_backend_data_t * backend_data ;
182
+ struct pollfd * pollfds ;
183
+ php_poll_event * events ;
184
+ int max_events ;
185
+ int event_count ;
186
+ } poll_result_context ;
187
+
188
+ /* Callback to process poll results */
189
+ static bool poll_process_results_callback (int fd , php_poll_fd_entry * entry , void * user_data )
190
+ {
191
+ poll_result_context * ctx = (poll_result_context * ) user_data ;
192
+
193
+ if (ctx -> event_count >= ctx -> max_events ) {
194
+ return false; /* Stop if events array is full */
244
195
}
245
- php_poll_fd_table_remove (backend_data -> fd_table , fd );
196
+
197
+ /* Find the corresponding pollfd entry */
198
+ for (int i = 0 ; i < php_poll_fd_table_count (ctx -> backend_data -> fd_table ); i ++ ) {
199
+ if (ctx -> pollfds [i ].fd == fd && ctx -> pollfds [i ].revents != 0 ) {
200
+ ctx -> events [ctx -> event_count ].fd = fd ;
201
+ ctx -> events [ctx -> event_count ].events = entry -> events ;
202
+ ctx -> events [ctx -> event_count ].revents
203
+ = poll_events_from_native (ctx -> pollfds [i ].revents );
204
+ ctx -> events [ctx -> event_count ].data = entry -> data ;
205
+ ctx -> event_count ++ ;
206
+ break ;
207
+ }
208
+ }
209
+
210
+ return true;
246
211
}
247
212
248
213
static int poll_backend_wait (php_poll_ctx * ctx , php_poll_event * events , int max_events , int timeout )
249
214
{
250
215
poll_backend_data_t * backend_data = (poll_backend_data_t * ) ctx -> backend_data ;
251
216
252
- if (backend_data -> fds_used == 0 ) {
253
- /* No FDs to monitor, but respect timeout */
217
+ int fd_count = php_poll_fd_table_count (backend_data -> fd_table );
218
+ if ( fd_count == 0 ) {
254
219
if (timeout > 0 ) {
255
220
struct timespec ts ;
256
221
ts .tv_sec = timeout / 1000 ;
@@ -260,35 +225,45 @@ static int poll_backend_wait(php_poll_ctx *ctx, php_poll_event *events, int max_
260
225
return 0 ;
261
226
}
262
227
263
- int nfds = poll (backend_data -> fds , backend_data -> fds_capacity , timeout );
264
-
265
- if (nfds > 0 ) {
266
- int event_count = 0 ;
267
- for (int i = 0 ; i < backend_data -> fds_capacity && event_count < max_events ; i ++ ) {
268
- if (backend_data -> fds [i ].fd != -1 && backend_data -> fds [i ].revents != 0 ) {
269
- php_poll_fd_entry * entry
270
- = php_poll_fd_table_find (backend_data -> fd_table , backend_data -> fds [i ].fd );
271
- if (entry ) {
272
- events [event_count ].fd = backend_data -> fds [i ].fd ;
273
- events [event_count ].events = entry -> events ;
274
- events [event_count ].revents
275
- = poll_events_from_native (backend_data -> fds [i ].revents );
276
- events [event_count ].data = entry -> data ;
277
- event_count ++ ;
278
- }
279
-
280
- backend_data -> fds [i ].revents = 0 ; /* Clear for next poll */
281
- }
228
+ /* Ensure temp_fds array is large enough */
229
+ if (fd_count > backend_data -> temp_fds_capacity ) {
230
+ struct pollfd * new_fds = php_poll_realloc (
231
+ backend_data -> temp_fds , fd_count * sizeof (struct pollfd ), ctx -> persistent );
232
+ if (!new_fds ) {
233
+ php_poll_set_error (ctx , PHP_POLL_ERR_NOMEM );
234
+ return -1 ;
282
235
}
236
+ backend_data -> temp_fds = new_fds ;
237
+ backend_data -> temp_fds_capacity = fd_count ;
238
+ }
239
+
240
+ /* Build pollfd array from fd_table */
241
+ poll_build_context build_ctx = { .fds = backend_data -> temp_fds , .index = 0 };
242
+ php_poll_fd_table_foreach (backend_data -> fd_table , poll_build_fds_callback , & build_ctx );
283
243
284
- /* Apply edge-trigger simulation using helper */
244
+ /* Call poll() */
245
+ int nfds = poll (backend_data -> temp_fds , fd_count , timeout );
246
+
247
+ if (nfds > 0 ) {
248
+ /* Process results */
249
+ poll_result_context result_ctx = { .backend_data = backend_data ,
250
+ .pollfds = backend_data -> temp_fds ,
251
+ .events = events ,
252
+ .max_events = max_events ,
253
+ .event_count = 0 };
254
+
255
+ php_poll_fd_table_foreach (
256
+ backend_data -> fd_table , poll_process_results_callback , & result_ctx );
257
+ int event_count = result_ctx .event_count ;
258
+
259
+ /* Apply edge-trigger simulation */
285
260
nfds = php_poll_simulate_edge_trigger (backend_data -> fd_table , events , event_count );
286
261
287
- /* Handle oneshot removals after simulation */
262
+ /* Handle oneshot removals */
288
263
for (int i = 0 ; i < nfds ; i ++ ) {
289
264
php_poll_fd_entry * entry = php_poll_fd_table_find (backend_data -> fd_table , events [i ].fd );
290
265
if (entry && (entry -> events & PHP_POLL_ONESHOT ) && events [i ].revents != 0 ) {
291
- poll_handle_oneshot_removal (backend_data , events [i ].fd );
266
+ php_poll_fd_table_remove (backend_data -> fd_table , events [i ].fd );
292
267
}
293
268
}
294
269
}
@@ -298,7 +273,7 @@ static int poll_backend_wait(php_poll_ctx *ctx, php_poll_event *events, int max_
298
273
299
274
static bool poll_backend_is_available (void )
300
275
{
301
- return true; /* poll() is always available */
276
+ return true;
302
277
}
303
278
304
279
static int poll_backend_get_suitable_max_events (php_poll_ctx * ctx )
@@ -310,12 +285,7 @@ static int poll_backend_get_suitable_max_events(php_poll_ctx *ctx)
310
285
}
311
286
312
287
int active_fds = php_poll_fd_table_count (backend_data -> fd_table );
313
-
314
- if (active_fds == 0 ) {
315
- return 1 ;
316
- }
317
-
318
- return active_fds ;
288
+ return active_fds == 0 ? 1 : active_fds ;
319
289
}
320
290
321
291
const php_poll_backend_ops php_poll_backend_poll_ops = {
@@ -329,7 +299,7 @@ const php_poll_backend_ops php_poll_backend_poll_ops = {
329
299
.wait = poll_backend_wait ,
330
300
.is_available = poll_backend_is_available ,
331
301
.get_suitable_max_events = poll_backend_get_suitable_max_events ,
332
- .supports_et = false, /* poll() doesn't support ET natively, but we simulate it */
302
+ .supports_et = false,
333
303
};
334
304
335
305
#endif /* HAVE_POLL */
0 commit comments