Hi! Looks like I’ve let the ball fall on this one :)
Discussion summary: Each time ev_io_set is being called, libev will assume that this is potentially a new file descriptor. Marc said it’s not ok to hack a watcher to disable this ev_io quirk when we know for sure that the descriptor is the old one. A lightweight variant of ev_io_set to switch R,W,RW watcher modes was requested and denied. I don’t intend to persist any further in hopes that Marc will change his mind :) Just a few observations though. a) I believe that documentation permits moving ev_io watcher to a different event loop without doing ev_io_set first. The loop will mishandle the descriptor since ev_io_start in the previous event loop has cleared the special flag set by ev_io_set. b) For a casual docs reader like myself it wasn’t obvious that multiple watchers for one descriptor should be used if switching between R,W,RW modes is desired. Probably a relevant example in the docs will help? Regards. > On 07 Nov 2015, at 20:00, Marc Lehmann <[email protected]> wrote: > > On Fri, Nov 06, 2015 at 05:25:38PM +0300, Nick Zavaritsky <[email protected]> > wrote: >>> I don't quite see why you couldn't reuse the I/O watcher? I also use >>> coroutines, and typically it is possible to reuse the watcher (for >>> performance reasons, it is basically always faster to reuse watchers). >> >> Technically, reusing is possible, though it will require a massive >> refactoring. And it will likely make the code somewhat more complicated. >> Probably it is the right thing to do anyway, but I would really like to >> research other options first. > > Are you sure it requires massive refactoring? While it might of course be > true, a simple (dynamic) array with a busy bit should already do and catch > most cases. Also, you already have to know whether your fd has changed or > not, how do you do that? Is this implicit in the code using your coroutine > layer? > > Also, you need to be clear on your goals - id you are ok with less > performance and simpler code, your goal is already reached, apparently. > >>> You can do whatever you want as long as you don't complain later, however, >>> libev doesn't really have a concept of "watcher flags" that is exposed. >> >> So switching between (say) EV_READ and (EV_READ | EV_WRITE) mode is only >> *officially* possible via ev_io_set, right? > > Yes. > >> It would be great if it was possible to switch modes without triggering the >> code that works around the problem of reused file descriptors. Though at the >> first glance it seams that going from EV_READ to (EV_READ | EV_WRITE) >> requires a syscall anyway, that is not necessary the case, please consider >> the following situations: > > I am not convinved it would be so great. All your problems go away with a > more efficient architecture: encouraging slower solutions is great why > exactly? > >> (1) multiple watchers for the same fd in the same loop, it is still possible >> that the ‘union’ mode didn’t change after all; >> (2) redundant R->RW->R mode switching before doing the next event loop >> iteration (I’ve actually asked about this use case on the mail list quite a >> while ago). > > For multiple watchers, this could indeed be optimised inside libev, maybe, > possibly. Yet again, it solves a problem that doesn't happen with typical > uses, and can be avoided by using a more efficient design for untypical > uses. > >> I suggest adding a lighter version of ev_io_set that > > I think that would complicate the API for users, without adding much > gain. I am not completely set in stone for this, but at the moment, your > argument, which I essentially understand as "I have a suboptimal design > to start with, so I want libev to waste some more efficiency and make it > harder to use by others, so my suboptimal design works a bit better". > > It might be possible to implement some multiple-watcher optimisation with > minimal overhead, which I might consider (and will look at when I have time), > but in general, having yet another abstraction layer to deal with a problem > that can be solved more efficiently already is not something I see as a > worthy goal. > > And in your case, if you have some generic coroutine layer somewhere, it would > seem especially reasonable to invest a bit of effort into making this as > efficient as > >> I would really like to reuse IO watchers if I could; however it is >> complicated — currently N coroutines can block waiting for the same object. >> We really depend on this feature. And we don’t know N beforehand. > > You could either add a waiting list to the watcher, or use some busy bit and > flal back to a separate watcher if the "normal" one is in use. The later > should be fine unless it is common for many coroutines to wait for the same > fd, and if it is common, I relly question your design (what's the point of > many coroutines to wait for read and write?). If it's a coroutine waiting > for read and another for write, then you can have two watchers for that. Or a > waiting list. > > And if it's just "in case" that you want to allow many coroutines to wait for > the same fd, then it wouldn't be common. > > -- > The choice of a Deliantra, the free code+content MORPG > -----==- _GNU_ http://www.deliantra.net > ----==-- _ generation > ---==---(_)__ __ ____ __ Marc Lehmann > --==---/ / _ \/ // /\ \/ / [email protected] > -=====/_/_//_/\_,_/ /_/\_\ _______________________________________________ libev mailing list [email protected] http://lists.schmorp.de/mailman/listinfo/libev
