Hi, On Tue, Dec 9, 2025 at 12:48 PM Derick Rethans <[email protected]> wrote:
> On Thu, 30 Oct 2025, Jakub Zelenka wrote: > > > I would like to introduce a new polling API RFC that is part of my > > stream evolution work: > > > > https://wiki.php.net/rfc/poll_api > > Under "Event Constants", I realised that we can't use enums for this > due to them needing to be OR'ed, but it would be nice if at some point > in the future we had a way of doing: PollEvent::Read | PollEvent::Write; > > I introduce \Io\Poll\Event enum. It doesn't allow ORing but all functions now accept array of those events which is hopefully good enough and cover this. If we ever introduced something like enum sets supporting OR operator, the functions could accept it in addition to the array. > The enum PollBackend (not sure if that needs to be a backed enum), but > this can not stand: > > case EventPorts = "eventport"; > > All the others have the case name and value the same, but this one > misses the 's'. > It's no longer a backed enum so this is sorted. > > /** > * Remove this watcher from the poll context > * > * After removal, the watcher becomes inactive and cannot be reused. > */ > public function remove(): void {} > > Wouldn't this leave the PollWatcher object as a zombie: ie, it exists, > but you can't do anything with it. Would it be possible to move this API > somewhere else, so that the memory manager can just destruct it and > release the object? > The PollWatcher was introduced on request from Bob so the new objects are not created after each polling. This should be more efficient but to be able to remove it, it needs to be done explicitly because the reference is held so we need to somehow inform context that it can be removed. I think we could introduce API to re-use it in the future but for now leaving clean up to GC is the way. Btw. there isActive() method that still works after removal and it returns false. The modification method will throw exception if used. If you have some suggestion for better API, I will be happy to consider it. > > * @param int $maxEvents Maximum number of events to return (-1 for > unlimited) > * @return array Array of PollWatcher instances that have triggered > events > * @throws PollException If the wait operation fails > */ > public function wait(int $timeout = -1, int $maxEvents = -1): array {} > > I am not sure if I like this returning an array. Would it perhaps be > better to always return 1 (or 0 in case of non-blocking) events, which > allows typing the return value as ?PollWatcher? > Returning just a single event is not ideal for performance if there are many events so not sure it should be the preferred usage of the API. > > Alternative, perhaps this can be split up into two methods, wait() and > waitMultiple() to be able to handle both approaches? > I would see it more like introducing waitSingle but it's basically just public function waitSingle(int $timeout = -1): ?PollWatcher { return $this->wait($timeout, 1)[0] ?? null; } so not sure if it's that useful. But if you think, it's worth it, I can add it..? > > Under "Future Scope", you have (for example) TimerHandle, but as that > will (have to) extend PollHandle, it makes little sense to have a > getFileDescriptor() method on PollHandle. The timer and signal are actually file descriptors on Linux (timerfd and signalfd) but you are right that this is not always the case. This is however internal and that abstract class offers a different API for internal extending that is more flexible. It means it won't call getFileDescriptor() for internal classes but use direct C API. That getFileDescriptor() is really meant for user classes that extend PollHandle so they do something rather than extending class with empty interface. > Perhaps there should be > another (abstract) class, so that you can have: > > - PollHandle > - FileDescriptorPollHandle > - StreamPollHandle > - SocketPollHandle > - CurlPollHandle > - TimerPollHandle > - SignalPollHandle > > So in this case I think I would need to come up with some different way how to allow polling without file descriptor for user classes otherwise user space class could extend PollHandle and it would just do nothing which I don't think is the right thing. I thought about it and I just don't have any idea what that could be. I think that non fd variants don't make much sense for user space or at least I don't see any reasonable use case. The only other concern I have is that some polling backends allow for > different events to be watched, which makes it harder to write portable > code. > I tried to make it as portable as possible but edge triggering is just not possible to simulate and I think it's worth exposing it even though it doesn't work on Windows and Solaris. I added at least flag in the backend so it's quite simple to check. Kind regards, Jakub
