On Fri, Aug 29, 2014 at 01:57:03PM +0200, Marc Lehmann <schm...@schmorp.de> wrote: > On Fri, Aug 29, 2014 at 01:49:46PM +0200, Hongli Lai <hon...@phusion.nl> > wrote: > > I know that libeio does not own the fd. But that was not my point. My point > > is: after libeio has created an fd with open(), > > Well, you haven't mentioned open so far, but even with open, all you need is > to find out whether the request is still needed, and if not, close the fd.
Anyways, we talked about this, and want to add something more. The libeio core (that is, not the convenience request submission wrappers such as eio_open, eio_read etc.) should definitely stay as it is (i.e. you need to deal with this in your destroy function). A case could be made for the convenience wrappers, such as eio_open - right now, if you just call eio_open and cancel the request, you might leak an fd. You would need to provide your own destroy function: eio_req *req = eio_open (...); req->destroy = my_destroy; and in my_destroy: if (EIO_CANCELLED (req) && req->resuit >= 0) close (req->result); This is annoying, and we are close to adding such code to the default destroy function for the convenience wrappers. However... [RATIONALE] [automatic behaviour for convenience wrapper default destroy functgion] After giving this more thought, we think this isn't as useful as it looks - again, what would the usecase be? Who calls eio_open to e.g. create a file, and then cancels it without wanting to know? Worse, how about eio_close - somebody who cancels eio_close is either rather confused, or really really needs her own destroy function. And this leads directly to the next problem: should the above call be close() or rather eio_close()? So we don't think cancellation can be "blind" - you have to know what you are doing, either by having a destroy functionb that cleans up the way you want it, or by not cancelling certain requests. The only use case for blind cancellation we could come up with is when you have outstanding eio requests for some higher-level request (e.g. a http request), and you want to cancel all outtsanding requests to clean up, because e.g. the connection died. But even in that case, you need to know what you are doing - if your request does eio_open, eio_read and eio_close, then you simply can't blindly cancel all requests - calling eio_close while eio_read is still outstanding can cause data corruption. Canceling eio_close might leak an fd. And how to cancel an eio_open that creates a file? unlink it? Sometimes, that would be the correct action. libeio can't really know about what to do, so while the default destroy function might be able to do some sensible default action, we think that this default action will only be executed in cases where the user likely is doing something wrong, by e.g. blindly canceling requests. This is why we think that such code would not really be useful, i.e. there is no sensible non-marginal use case. So the rule should be, when you cancel requests, you need to have custom code to deal with the case where it was executed, and "undo" it in the way required by your application. [call finish callback on success] We also thought about invoking the request/finish callback on cancelled requests iff the request was successful (or alternatively, if it was attempted). In that case, the only strongly affected calls are close, dup2, open, wd_close and wd_open (and in the future possibly mmap). Calls such as mlockall have process-visible effects, but usually require sequencing (e.g. after mmap, before munmap). Calls such as eio_readdir or eio_stat, which allocate memory, already do free this on canceled requests. So again, the argument woluld be that only the user can really know whether this is useful behaviour, and when you cancel an eio_dup2 for example, you will need to know what you are doing (and what has been done). [summary] So, while a limited case can be made for the convenience wrappers, which by default can leak fds on e.g. close and open, this is not different than leaking memory or disk space on mmap or write (it can be quite bad: what happens when you cancel a thread that is in a close() for example), and libeio isn't the place to decide what to do in those cases. For requests such as eio_read, eio_stat, eio_readahead, eio_sendfile, eio_fsync or eio_fchmod, cancellation is generally without ill effects, and these requests generallya comprise the majority of uses. So in the normal case, libeio is convenient and doesn't force the user to do extra work. For requests such as eio_open or eio_close, the user will have to specify what to do when a cancellation was too late. -- The choice of a Deliantra, the free code+content MORPG -----==- _GNU_ http://www.deliantra.net ----==-- _ generation ---==---(_)__ __ ____ __ Marc Lehmann --==---/ / _ \/ // /\ \/ / schm...@schmorp.de -=====/_/_//_/\_,_/ /_/\_\ _______________________________________________ libev mailing list libev@lists.schmorp.de http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev