1717#include "zend_exceptions.h"
1818#include "php_network.h"
1919#include "php_poll.h"
20+ #include "io_poll.h"
2021#include "io_poll_arginfo.h"
2122#include "io_poll_decl.h"
2223
@@ -54,6 +55,8 @@ typedef struct php_io_poll_watcher_object {
5455 zval data ;
5556 bool active ;
5657 php_io_poll_context_object * context ; /* Back reference to Context object */
58+ php_socket_t fd ;
59+ php_stream * stream ;
5760 zend_object std ;
5861} php_io_poll_watcher_object ;
5962
@@ -66,7 +69,6 @@ struct php_io_poll_context_object {
6669
6770/* Stream poll handle specific data */
6871typedef struct php_stream_poll_handle_data {
69- php_stream * stream ;
7072 zend_resource * res ;
7173} php_stream_poll_handle_data ;
7274
@@ -179,16 +181,24 @@ static const char *php_io_poll_backend_type_to_name(php_poll_backend_type type)
179181
180182/* Stream Poll Handle Implementation */
181183
184+ static zend_always_inline php_stream * php_stream_poll_handle_get_stream (php_stream_poll_handle_data * data )
185+ {
186+ if (!data || !data -> res ) {
187+ return NULL ;
188+ }
189+ return (php_stream * ) zend_fetch_resource2 (data -> res , NULL , php_file_le_stream (), php_file_le_pstream ());
190+ }
191+
182192static php_socket_t php_stream_poll_handle_get_fd (php_poll_handle_object * handle )
183193{
184- php_stream_poll_handle_data * data = handle -> handle_data ;
194+ php_stream * stream = php_stream_poll_handle_get_stream ( handle -> handle_data ) ;
185195 php_socket_t fd ;
186196
187- if (!data || ! data -> stream ) {
197+ if (!stream ) {
188198 return SOCK_ERR ;
189199 }
190200
191- if (php_stream_cast (data -> stream , PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL ,
201+ if (php_stream_cast (stream , PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL ,
192202 (void * ) & fd , 1 )
193203 != SUCCESS
194204 || fd == -1 ) {
@@ -200,8 +210,8 @@ static php_socket_t php_stream_poll_handle_get_fd(php_poll_handle_object *handle
200210
201211static int php_stream_poll_handle_is_valid (php_poll_handle_object * handle )
202212{
203- php_stream_poll_handle_data * data = handle -> handle_data ;
204- return data && data -> stream && !php_stream_eof (data -> stream );
213+ php_stream * stream = php_stream_poll_handle_get_stream ( handle -> handle_data ) ;
214+ return stream && !php_stream_eof (stream );
205215}
206216
207217static void php_stream_poll_handle_cleanup (php_poll_handle_object * handle )
@@ -254,6 +264,8 @@ static zend_object *php_io_poll_watcher_create_object(zend_class_entry *ce)
254264 intern -> triggered_events = 0 ;
255265 intern -> active = false;
256266 intern -> context = NULL ;
267+ intern -> fd = SOCK_ERR ;
268+ intern -> stream = NULL ;
257269 ZVAL_NULL (& intern -> data );
258270
259271 return & intern -> std ;
@@ -272,12 +284,94 @@ static zend_object *php_io_poll_context_create_object(zend_class_entry *ce)
272284 return & intern -> std ;
273285}
274286
287+ static zend_always_inline zend_ulong php_io_poll_compute_ptr_key (void * ptr )
288+ {
289+ zend_ulong key = (zend_ulong ) (uintptr_t ) ptr ;
290+ return (key >> 3 ) | (key << ((sizeof (key ) * 8 ) - 3 ));
291+ }
292+
293+ static zend_always_inline php_stream * php_io_poll_watcher_get_stream (php_io_poll_watcher_object * watcher )
294+ {
295+ if (!watcher -> handle || watcher -> handle -> ops != & php_stream_poll_handle_ops ) {
296+ return NULL ;
297+ }
298+ return php_stream_poll_handle_get_stream (watcher -> handle -> handle_data );
299+ }
300+
301+ static void php_io_poll_stream_watch (php_stream * stream , php_io_poll_watcher_object * watcher )
302+ {
303+ if (!stream -> poll_watchers ) {
304+ stream -> poll_watchers = pemalloc (sizeof (HashTable ), stream -> is_persistent );
305+ zend_hash_init (stream -> poll_watchers , 4 , NULL , NULL , stream -> is_persistent );
306+ }
307+
308+ zval zv ;
309+ ZVAL_PTR (& zv , watcher );
310+ zend_hash_index_update (stream -> poll_watchers , php_io_poll_compute_ptr_key (watcher ), & zv );
311+ }
312+
313+ static void php_io_poll_stream_unwatch (php_io_poll_watcher_object * watcher )
314+ {
315+ php_stream * stream = watcher -> stream ;
316+ watcher -> stream = NULL ;
317+
318+ if (!stream || !stream -> poll_watchers ) {
319+ return ;
320+ }
321+
322+ zend_hash_index_del (stream -> poll_watchers , php_io_poll_compute_ptr_key (watcher ));
323+
324+ if (zend_hash_num_elements (stream -> poll_watchers ) == 0 ) {
325+ zend_hash_destroy (stream -> poll_watchers );
326+ pefree (stream -> poll_watchers , stream -> is_persistent );
327+ stream -> poll_watchers = NULL ;
328+ }
329+ }
330+
331+ PHPAPI void php_io_poll_stream_notify_close (php_stream * stream )
332+ {
333+ HashTable * watchers = stream -> poll_watchers ;
334+ if (!watchers ) {
335+ return ;
336+ }
337+ stream -> poll_watchers = NULL ;
338+
339+ ZEND_HASH_FOREACH_VAL (watchers , zval * zv ) {
340+ GC_ADDREF (& ((php_io_poll_watcher_object * ) Z_PTR_P (zv ))-> std );
341+ } ZEND_HASH_FOREACH_END ();
342+
343+ ZEND_HASH_FOREACH_VAL (watchers , zval * zv ) {
344+ php_io_poll_watcher_object * watcher = Z_PTR_P (zv );
345+ php_io_poll_context_object * context = watcher -> context ;
346+ watcher -> stream = NULL ;
347+ if (context ) {
348+ if (watcher -> fd != SOCK_ERR && context -> ctx ) {
349+ php_poll_remove (context -> ctx , (int ) watcher -> fd );
350+ }
351+ watcher -> active = false;
352+ watcher -> context = NULL ;
353+ if (context -> watchers ) {
354+ zend_hash_index_del (context -> watchers , php_io_poll_compute_ptr_key (watcher -> handle ));
355+ }
356+ }
357+ } ZEND_HASH_FOREACH_END ();
358+
359+ ZEND_HASH_FOREACH_VAL (watchers , zval * zv ) {
360+ OBJ_RELEASE (& ((php_io_poll_watcher_object * ) Z_PTR_P (zv ))-> std );
361+ } ZEND_HASH_FOREACH_END ();
362+
363+ zend_hash_destroy (watchers );
364+ pefree (watchers , stream -> is_persistent );
365+ }
366+
275367/* Object Destruction Functions */
276368
277369static void php_io_poll_watcher_free_object (zend_object * obj )
278370{
279371 php_io_poll_watcher_object * intern = PHP_POLL_WATCHER_OBJ_FROM_ZOBJ (obj );
280372
373+ php_io_poll_stream_unwatch (intern );
374+
281375 zval_ptr_dtor (& intern -> data );
282376
283377 if (intern -> handle ) {
@@ -294,6 +388,7 @@ static void php_io_poll_context_free_object(zend_object *obj)
294388 if (intern -> watchers ) {
295389 ZEND_HASH_FOREACH_VAL (intern -> watchers , zval * zv ) {
296390 php_io_poll_watcher_object * watcher = PHP_POLL_WATCHER_OBJ_FROM_ZOBJ (Z_OBJ_P (zv ));
391+ php_io_poll_stream_unwatch (watcher );
297392 watcher -> active = false;
298393 watcher -> context = NULL ;
299394 } ZEND_HASH_FOREACH_END ();
@@ -340,14 +435,6 @@ static HashTable *php_io_poll_context_get_gc(zend_object *obj, zval **table, int
340435 return NULL ;
341436}
342437
343- /* Utility functions */
344-
345- static zend_always_inline zend_ulong php_io_poll_compute_ptr_key (void * ptr )
346- {
347- zend_ulong key = (zend_ulong ) (uintptr_t ) ptr ;
348- return (key >> 3 ) | (key << ((sizeof (key ) * 8 ) - 3 ));
349- }
350-
351438static zend_result php_io_poll_watcher_modify_events (
352439 php_io_poll_watcher_object * watcher , uint32_t events )
353440{
@@ -357,7 +444,7 @@ static zend_result php_io_poll_watcher_modify_events(
357444 return FAILURE ;
358445 }
359446
360- php_socket_t fd = php_poll_handle_get_fd ( watcher -> handle ) ;
447+ php_socket_t fd = watcher -> fd ;
361448 if (fd == SOCK_ERR ) {
362449 zend_throw_exception (
363450 php_io_poll_invalid_handle_class_entry , "Invalid handle for polling" , 0 );
@@ -453,7 +540,6 @@ PHP_METHOD(StreamPollHandle, __construct)
453540
454541 /* Set up stream-specific data */
455542 php_stream_poll_handle_data * data = emalloc (sizeof (php_stream_poll_handle_data ));
456- data -> stream = stream ;
457543 data -> res = stream -> res ;
458544 intern -> handle_data = data ;
459545
@@ -466,14 +552,14 @@ PHP_METHOD(StreamPollHandle, getStream)
466552 ZEND_PARSE_PARAMETERS_NONE ();
467553
468554 php_poll_handle_object * intern = PHP_POLL_HANDLE_OBJ_FROM_ZV (getThis ());
469- php_stream_poll_handle_data * data = intern -> handle_data ;
555+ php_stream * stream = php_stream_poll_handle_get_stream ( intern -> handle_data ) ;
470556
471- if (!data || ! data -> stream ) {
557+ if (!stream ) {
472558 RETURN_NULL ();
473559 }
474560
475- GC_ADDREF (data -> stream -> res );
476- php_stream_to_zval (data -> stream , return_value );
561+ GC_ADDREF (stream -> res );
562+ php_stream_to_zval (stream , return_value );
477563}
478564
479565PHP_METHOD (StreamPollHandle , isValid )
@@ -645,13 +731,15 @@ PHP_METHOD(Io_Poll_Watcher, remove)
645731 php_poll_ctx * poll_ctx = context -> ctx ;
646732 HashTable * watchers = context -> watchers ;
647733 zend_ulong hash_key = php_io_poll_compute_ptr_key (intern -> handle );
648- php_socket_t fd = php_poll_handle_get_fd (intern -> handle );
649- if (fd != SOCK_ERR ) {
650- php_poll_remove (poll_ctx , (int ) fd );
734+ if (intern -> fd != SOCK_ERR ) {
735+ php_poll_remove (poll_ctx , (int ) intern -> fd );
651736 }
652737
738+ php_io_poll_stream_unwatch (intern );
739+
653740 intern -> active = false;
654741 intern -> context = NULL ;
742+ intern -> fd = SOCK_ERR ;
655743
656744 if (watchers ) {
657745 zend_hash_index_del (watchers , hash_key );
@@ -770,6 +858,13 @@ PHP_METHOD(Io_Poll_Context, add)
770858
771859 watcher -> active = true;
772860 watcher -> context = intern ;
861+ watcher -> fd = fd ;
862+
863+ php_stream * watched_stream = php_io_poll_watcher_get_stream (watcher );
864+ if (watched_stream ) {
865+ watcher -> stream = watched_stream ;
866+ php_io_poll_stream_watch (watched_stream , watcher );
867+ }
773868}
774869
775870PHP_METHOD (Io_Poll_Context , wait )
0 commit comments