--- libeio/eio.pod 2011/07/05 20:38:47 1.19 +++ libeio/eio.pod 2011/07/24 03:32:54 1.27 @@ -47,21 +47,24 @@ =head2 FORK SUPPORT -Calling C is fully supported by this module - but you must not -rely on this. It is currently implemented in these steps: - - 1. wait till all requests in "execute" state have been handled - (basically requests that are already handed over to the kernel). - 2. fork - 3. in the parent, continue business as usual, done - 4. in the child, destroy all ready and pending requests and free the - memory used by the worker threads. This gives you a fully empty - libeio queue. - -Note, however, since libeio does use threads, the above guarantee doesn't -cover your libc, for example, malloc and other libc functions are not -fork-safe, so there is very little you can do after a fork, and in fact, -the above might crash, and thus change. +Usage of pthreads in a program changes the semantics of fork +considerably. Specifically, only async-safe functions can be called after +fork. Libeio uses pthreads, so this applies, and makes using fork hard for +anything but relatively fork + exec uses. + +This library only works in the process that initialised it: Forking is +fully supported, but using libeio in any other process than the one that +called C is not. + +You might get around by not I libeio before (or after) forking in +the parent, and using it in the child afterwards. You could also try to +call the L function again in the child, which will brutally +reinitialise all data structures, which isn't POSIX conformant, but +typically works. + +Otherwise, the only recommendation you should follow is: treat fork code +the same way you treat signal handlers, and only ever call C in +the process that uses it, and only once ever. =head1 INITIALISATION/INTEGRATION @@ -81,6 +84,9 @@ It accepts two function pointers specifying callbacks as argument, both of which can be C<0>, in which case the callback isn't called. +There is currently no way to change these callbacks later, or to +"uninitialise" the library again. + =item want_poll callback The C callback is invoked whenever libeio wants attention (i.e. @@ -133,7 +139,7 @@ (i.e. it returns C<-1>) then you should start an idle watcher that calls C until it returns something C. -A full-featured conenctor between libeio and libev would look as follows +A full-featured connector between libeio and libev would look as follows (if C is handling all requests, it can of course be simplified a lot by removing the idle watcher logic): @@ -407,9 +413,10 @@ =item eio_realpath (const char *path, int pri, eio_cb cb, void *data) -Similar to the realpath libc function, but unlike that one, result is -C<-1> on failure and the length of the returned path in C (which is -not 0-terminated) - this is similar to readlink. +Similar to the realpath libc function, but unlike that one, C<< +req->result >> is C<-1> on failure. On success, the result is the length +of the returned path in C (which is I 0-terminated) - this is +similar to readlink. =item eio_stat (const char *path, int pri, eio_cb cb, void *data) @@ -587,6 +594,13 @@ Calls C. If the syscall is missing, then the call is emulated by simply reading the data (currently in 64kiB chunks). +=item eio_syncfs (int fd, int pri, eio_cb cb, void *data) + +Calls Linux' C syscall, if available. Returns C<-1> and sets +C to C if the call is missing I, +if the C is C<< >= 0 >>, so you can probe for the availability of the +syscall with a negative C argument and checking for C<-1/ENOSYS>. + =item eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data) Calls C. If the syscall is missing, then this is the same @@ -595,6 +609,15 @@ Flags can be any combination of C, C and C. +=item eio_fallocate (int fd, int mode, off_t offset, off_t len, int pri, eio_cb cb, void *data) + +Calls C (note: I C!). If the syscall is +missing, then it returns failure and sets C to C. + +The C argument can be C<0> (for behaviour similar to +C), or C, which keeps the size +of the file unchanged (but still preallocates space beyond end of file). + =back =head3 LIBEIO-SPECIFIC REQUESTS @@ -679,7 +702,8 @@ =item eio_req *grp = eio_grp (eio_cb cb, void *data) -Creates, submits and returns a group request. +Creates, submits and returns a group request. Note that it doesn't have a +priority, unlike all other requests. =item eio_grp_add (eio_req *grp, eio_req *req) @@ -688,23 +712,78 @@ =item eio_grp_cancel (eio_req *grp) Cancels all requests I the group, but I the group request -itself. You can cancel the group request via a normal C call. +itself. You can cancel the group request I all subrequests via a +normal C call. + +=back + +=head4 GROUP REQUEST LIFETIME + +Left alone, a group request will instantly move to the pending state and +will be finished at the next call of C. + +The usefulness stems from the fact that, if a subrequest is added to a +group I a call to C, via C, then the group +will not finish until all the subrequests have finished. + +So the usage cycle of a group request is like this: after it is created, +you normally instantly add a subrequest. If none is added, the group +request will finish on it's own. As long as subrequests are added before +the group request is finished it will be kept from finishing, that is the +callbacks of any subrequests can, in turn, add more requests to the group, +and as long as any requests are active, the group request itself will not +finish. + +=head4 CREATING COMPOSITE REQUESTS +Imagine you wanted to create an C request that opens a file, +reads it and closes it. This means it has to execute at least three eio +requests, but for various reasons it might be nice if that request looked +like any other eio request. +This can be done with groups: + +=over 4 + +=item 1) create the request object + +Create a group that contains all further requests. This is the request you +can return as "the load request". + +=item 2) open the file, maybe + +Next, open the file with C and add the request to the group +request and you are finished setting up the request. + +If, for some reason, you cannot C (path is a null ptr?) you +can set C<< grp->result >> to C<-1> to signal an error and let the group +request finish on its own. + +=item 3) open callback adds more requests + +In the open callback, if the open was not successful, copy C<< +req->errorno >> to C<< grp->errorno >> and set C<< grp->errorno >> to +C<-1> to signal an error. + +Otherwise, malloc some memory or so and issue a read request, adding the +read request to the group. + +=item 4) continue issuing requests till finished + +In the real callback, check for errors and possibly continue with +C or any other eio request in the same way. + +As soon as no new requests are added the group request will finish. Make +sure you I set C<< grp->result >> to some sensible value. =back +=head4 REQUEST LIMITING #TODO -/*****************************************************************************/ -/* groups */ - -eio_req *eio_grp (eio_cb cb, void *data); -void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit); void eio_grp_limit (eio_req *grp, int limit); -void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the group */ =back @@ -845,7 +924,7 @@ requests, you might want to increase this. If this symbol is undefined (the default) then libeio will use its default -stack size (C currently). If it is defined, but +stack size (C currently). If it is defined, but C<0>, then the default operating system stack size will be used. In all other cases, the value must be an expression that evaluates to the desired stack size.