--- IO-AIO/AIO.pm 2007/10/06 14:05:19 1.117 +++ IO-AIO/AIO.pm 2008/04/16 16:45:18 1.121 @@ -28,10 +28,13 @@ my $grp = aio_group sub { print "all stats done\n" }; add $grp aio_stat "..." for ...; - # AnyEvent integration + # AnyEvent integration (EV, Event, Glib, Tk, urxvt, pureperl...) open my $fh, "<&=" . IO::AIO::poll_fileno or die "$!"; my $w = AnyEvent->io (fh => $fh, poll => 'r', cb => sub { IO::AIO::poll_cb }); + # EV integration + my $w = EV::io IO::AIO::poll_fileno, EV::READ, \&IO::AIO::poll_cb; + # Event integration Event->io (fd => IO::AIO::poll_fileno, poll => 'r', @@ -193,13 +196,16 @@ use base 'Exporter'; BEGIN { - our $VERSION = '2.51'; + our $VERSION = '2.61'; + + our @AIO_REQ = qw(aio_sendfile aio_read aio_write aio_open aio_close + aio_stat aio_lstat aio_unlink aio_rmdir aio_readdir + aio_scandir aio_symlink aio_readlink aio_sync aio_fsync + aio_fdatasync aio_pathsync aio_readahead + aio_rename aio_link aio_move aio_copy aio_group + aio_nop aio_mknod aio_load aio_rmtree aio_mkdir aio_chown + aio_chmod aio_utime aio_truncate); - our @AIO_REQ = qw(aio_sendfile aio_read aio_write aio_open aio_close aio_stat - aio_lstat aio_unlink aio_rmdir aio_readdir aio_scandir aio_symlink - aio_readlink aio_fsync aio_fdatasync aio_readahead aio_rename aio_link - aio_move aio_copy aio_group aio_nop aio_mknod aio_load aio_rmtree aio_mkdir - aio_chown aio_chmod aio_utime aio_truncate); our @EXPORT = (@AIO_REQ, qw(aioreq_pri aioreq_nice aio_block)); our @EXPORT_OK = qw(poll_fileno poll_cb poll_wait flush min_parallel max_parallel max_idle @@ -318,66 +324,17 @@ code. Unfortunately, you can't do this to perl. Perl I very strongly on -closing the file descriptor associated with the filehandle itself. Here is -what aio_close will try: +closing the file descriptor associated with the filehandle itself. - 1. dup()licate the fd - 2. asynchronously close() the duplicated fd - 3. dup()licate the fd once more - 4. let perl close() the filehandle - 5. asynchronously close the duplicated fd - -The idea is that the first close() flushes stuff to disk that closing an -fd will flush, so when perl closes the fd, nothing much will need to be -flushed. The second async. close() will then flush stuff to disk that -closing the last fd to the file will flush. - -Just FYI, SuSv3 has this to say on close: - - All outstanding record locks owned by the process on the file - associated with the file descriptor shall be removed. - - If fildes refers to a socket, close() shall cause the socket to be - destroyed. ... close() shall block for up to the current linger - interval until all data is transmitted. - [this actually sounds like a specification bug, but who knows] +Therefore, C will not close the filehandle - instead it will +use dup2 to overwrite the file descriptor with the write-end of a pipe +(the pipe fd will be created on demand and will be cached). -And at least Linux additionally actually flushes stuff on every close, -even when the file itself is still open. - -Sounds enourmously inefficient and complicated? Yes... please show me how -to nuke perl's fd out of existence... +Or in other words: the file descriptor will be closed, but it will not be +free for reuse until the perl filehandle is closed. =cut -sub aio_close($;$) { - aio_block { - my ($fh, $cb) = @_; - - my $pri = aioreq_pri; - my $grp = aio_group $cb; - - my $fd = fileno $fh; - - defined $fd or Carp::croak "aio_close called with fd-less filehandle"; - - # if the dups fail we will simply get EBADF - my $fd2 = _dup $fd; - aioreq_pri $pri; - add $grp _aio_close $fd2, sub { - my $fd2 = _dup $fd; - close $fh; - aioreq_pri $pri; - add $grp _aio_close $fd2, sub { - $grp->result ($_[0]); - }; - }; - - $grp - } -} - - =item aio_read $fh,$offset,$length, $data,$dataoffset, $callback->($retval) =item aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) @@ -649,7 +606,9 @@ utime $stat[8], $stat[9], $dst; chmod $stat[2] & 07777, $dst_fh; chown $stat[4], $stat[5], $dst_fh; - close $dst_fh; + + aioreq_pri $pri; + add $grp aio_close $dst_fh; } else { $grp->result (-1); close $src_fh; @@ -892,6 +851,10 @@ } } +=item aio_sync $callback->($status) + +Asynchronously call sync and call the callback when finished. + =item aio_fsync $fh, $callback->($status) Asynchronously call fsync on the given filehandle and call the callback @@ -905,6 +868,46 @@ If this call isn't available because your OS lacks it or it couldn't be detected, it will be emulated by calling C instead. +=item aio_pathsync $path, $callback->($status) + +This request tries to open, fsync and close the given path. This is a +composite request intended tosync directories after directory operations +(E.g. rename). This might not work on all operating systems or have any +specific effect, but usually it makes sure that directory changes get +written to disc. It works for anything that can be opened for read-only, +not just directories. + +Passes C<0> when everything went ok, and C<-1> on error. + +=cut + +sub aio_pathsync($;$) { + aio_block { + my ($path, $cb) = @_; + + my $pri = aioreq_pri; + my $grp = aio_group $cb; + + aioreq_pri $pri; + add $grp aio_open $path, O_RDONLY, 0, sub { + my ($fh) = @_; + if ($fh) { + aioreq_pri $pri; + add $grp aio_fsync $fh, sub { + $grp->result ($_[0]); + + aioreq_pri $pri; + add $grp aio_close $fh; + }; + } else { + $grp->result (-1); + } + }; + + $grp + } +} + =item aio_group $callback->(...) This is a very special aio request: Instead of doing something, it is a @@ -1050,7 +1053,7 @@ =item $grp->result (...) Set the result value(s) that will be passed to the group callback when all -subrequests have finished and set thre groups errno to the current value +subrequests have finished and set the groups errno to the current value of errno (just like calling C without an error number). By default, no argument will be passed and errno is zero.