Streams Poll API#19572
Conversation
|
Currently just kqueue and poll on MacOS are properly tested. The epoll should be easy to get tested but will need to then properly look to iocp and event ports. For event ports I will need to first set OmniOS (Illumos) up. |
|
So epoll looks good and all tests passing there. Tha API also builds on Windows but unsuprisingly the iocp backend does not really work well so this is someting that I will be looking to. And then event ports will likely need some work as well which I will look then too. |
2d53464 to
4edefc1
Compare
e2f2ec8 to
22689ad
Compare
a68b8be to
1d55dce
Compare
a74b2b8 to
d48b64f
Compare
9c3c346 to
1378608
Compare
This introduces various IO polling backend including epoll, kqueue, event ports, poll and WSAPoll. It makes the usage compatible between backends.
It makes use of internal polling API and exposes its functionality to user space.
| } | ||
| ?> | ||
| --EXPECT-- | ||
| ERROR: Handle already added |
There was a problem hiding this comment.
why do we need to throw when this happens? can't we just ignore?
There was a problem hiding this comment.
The issue is that the second call can have different events and data and that would get completely ignored. I should probably change the second call to:
pt_stream_poll_add($poll_ctx, $socket1w, [Io\Poll\Event::Read], "socket_ignored_data_and_event");to make it clearer...
There was a problem hiding this comment.
well that read even doesn't really make much sense for write socket but you get what I mean :)
DanielEScherzer
left a comment
There was a problem hiding this comment.
not going to pretend like I fully understand this, but some comments
| ]) | ||
|
|
||
| dnl Set poll mechanisms including poll that is always available | ||
| poll_mechanisms="$poll_mechanisms poll" |
There was a problem hiding this comment.
not sure if this matters, but $poll_mechanisms will always have a leading space (unless autoconf removes those automatically???) - if you start with poll being included at the top, then there wouldn't be that space
| +----------------------------------------------------------------------+ | ||
| | Copyright (c) The PHP Group | | ||
| +----------------------------------------------------------------------+ | ||
| | This source file is subject to version 3.01 of the PHP license, | |
There was a problem hiding this comment.
will need update for the license change
|
|
||
| /* Accessor macros */ | ||
| #define PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(_obj) \ | ||
| ((php_io_poll_context_object *) ((char *) (_obj) - XtOffsetOf(php_io_poll_context_object, std))) |
There was a problem hiding this comment.
will need update for XtOffsetOf removal
| #define PHP_POLL_CONTEXT_OBJ_FROM_ZV(_zv) PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(Z_OBJ_P(_zv)) | ||
|
|
||
| /* Helper to throw failed operation exceptions with error code */ | ||
| static inline void php_io_poll_throw_failed_operation( |
There was a problem hiding this comment.
I'm not sure that this kind of helper function actually helps - it me, it just adds another level of indirection. C.f. #21399 - what is the issue with using zend_throw_exception directly?
| case PHP_POLL_BACKEND_WSAPOLL: | ||
| return "WSAPoll"; | ||
| case PHP_POLL_BACKEND_AUTO: | ||
| default: |
There was a problem hiding this comment.
I would suggest that default be marked as unreachable rather than working - if someone casts an invalid integer to php_poll_backend_type we should fail loudly imo
| PHPAPI bool php_poll_backend_supports_edge_triggering(php_poll_backend_type backend) | ||
| { | ||
| if (backend == PHP_POLL_BACKEND_AUTO) { | ||
| /* Check the first (best) available backend */ | ||
| if (num_registered_backends > 0 && registered_backends[0]) { | ||
| return registered_backends[0]->supports_et; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| for (int i = 0; i < num_registered_backends; i++) { | ||
| if (registered_backends[i] && registered_backends[i]->type == backend) { | ||
| return registered_backends[i]->supports_et; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
seems like this can be deduplicated with php_poll_get_backend_ops()
| PHPAPI bool php_poll_backend_supports_edge_triggering(php_poll_backend_type backend) | |
| { | |
| if (backend == PHP_POLL_BACKEND_AUTO) { | |
| /* Check the first (best) available backend */ | |
| if (num_registered_backends > 0 && registered_backends[0]) { | |
| return registered_backends[0]->supports_et; | |
| } | |
| return false; | |
| } | |
| for (int i = 0; i < num_registered_backends; i++) { | |
| if (registered_backends[i] && registered_backends[i]->type == backend) { | |
| return registered_backends[i]->supports_et; | |
| } | |
| } | |
| return false; | |
| } | |
| PHPAPI bool php_poll_backend_supports_edge_triggering(php_poll_backend_type backend) | |
| { | |
| const php_poll_backend_ops *backend_ops = php_poll_get_backend_ops(backend); | |
| return backend_ops && backend_ops->supports_et; | |
| } |
| } | ||
|
|
||
| /* Get backend name */ | ||
| PHPAPI const char *php_poll_backend_name(php_poll_ctx *ctx) |
There was a problem hiding this comment.
can you document why this function and the ones below support having a missing context? Or a context with no backend_ops set? That seems confusing
| php_poll_handle_ops php_poll_handle_default_ops = { .get_fd = php_poll_handle_default_get_fd, | ||
| .is_valid = php_poll_handle_default_is_valid, | ||
| .cleanup = php_poll_handle_default_cleanup }; |
There was a problem hiding this comment.
this is a bit hard to read, suggest formatting like the other struct initializations
| php_poll_handle_ops php_poll_handle_default_ops = { .get_fd = php_poll_handle_default_get_fd, | |
| .is_valid = php_poll_handle_default_is_valid, | |
| .cleanup = php_poll_handle_default_cleanup }; | |
| php_poll_handle_ops php_poll_handle_default_ops = { | |
| .get_fd = php_poll_handle_default_get_fd, | |
| .is_valid = php_poll_handle_default_is_valid, | |
| .cleanup = php_poll_handle_default_cleanup | |
| }; |
| #define PHP_POLL_ERROR_CODE_NOSUPPORT 11 | ||
|
|
||
| /* Error codes */ | ||
| typedef enum { |
There was a problem hiding this comment.
I guess I'm a bit confused as to the difference between the defined codes and the corresponding enum cases - why not always use the enum cases, and just put the underlying literals integers in the enum definition?
| * @param handle The handle object | ||
| * @return true if valid, false if invalid | ||
| */ | ||
| int (*is_valid)(php_poll_handle_object *handle); |
There was a problem hiding this comment.
the documentation says that this returns true/false
| int (*is_valid)(php_poll_handle_object *handle); | |
| bool (*is_valid)(php_poll_handle_object *handle); |
This introduces a new API for polling that supports various backends:
The API tries to reflect primarily epoll and the rest is done in a way so it is compatible.
RFC: https://wiki.php.net/rfc/poll_api