--- IO-AIO/AIO.pm 2018/08/25 19:59:18 1.295 +++ IO-AIO/AIO.pm 2023/09/27 03:09:57 1.319 @@ -173,7 +173,7 @@ use base 'Exporter'; BEGIN { - our $VERSION = 4.6; + our $VERSION = 4.80; our @AIO_REQ = qw(aio_sendfile aio_seek aio_read aio_write aio_open aio_close aio_stat aio_lstat aio_unlink aio_rmdir aio_readdir aio_readdirx @@ -194,7 +194,12 @@ nreqs nready npending nthreads max_poll_time max_poll_reqs sendfile fadvise madvise - mmap munmap mremap munlock munlockall); + mmap munmap mremap munlock munlockall + + accept4 tee splice pipe2 pipesize + fexecve mount umount memfd_create eventfd + timerfd_create timerfd_settime timerfd_gettime + pidfd_open pidfd_send_signal pidfd_getfd); push @AIO_REQ, qw(aio_busy); # not exported @@ -280,11 +285,15 @@ IO::AIO::nreqs IO::AIO::nready IO::AIO::npending - $nfd = IO::AIO::get_fdlimit [EXPERIMENTAL] - IO::AIO::min_fdlimit $nfd [EXPERIMENTAL] + IO::AIO::reinit + + $nfd = IO::AIO::get_fdlimit + IO::AIO::min_fdlimit $nfd IO::AIO::sendfile $ofh, $ifh, $offset, $count IO::AIO::fadvise $fh, $offset, $len, $advice + IO::AIO::fexecve $fh, $argv, $envp + IO::AIO::mmap $scalar, $length, $prot, $flags[, $fh[, $offset]] IO::AIO::munmap $scalar IO::AIO::mremap $scalar, $new_length, $flags[, $new_address] @@ -293,6 +302,36 @@ IO::AIO::munlock $scalar, $offset = 0, $length = undef IO::AIO::munlockall + # stat extensions + $counter = IO::AIO::st_gen + $seconds = IO::AIO::st_atime, IO::AIO::st_mtime, IO::AIO::st_ctime, IO::AIO::st_btime + ($atime, $mtime, $ctime, $btime, ...) = IO::AIO::st_xtime + $nanoseconds = IO::AIO::st_atimensec, IO::AIO::st_mtimensec, IO::AIO::st_ctimensec, IO::AIO::st_btimensec + $seconds = IO::AIO::st_btimesec + ($atime, $mtime, $ctime, $btime, ...) = IO::AIO::st_xtimensec + + # very much unportable syscalls + IO::AIO::accept4 $r_fh, $sockaddr, $sockaddr_len, $flags + IO::AIO::splice $r_fh, $r_off, $w_fh, $w_off, $length, $flags + IO::AIO::tee $r_fh, $w_fh, $length, $flags + + $actual_size = IO::AIO::pipesize $r_fh[, $new_size] + ($rfh, $wfh) = IO::AIO::pipe2 [$flags] + + $fh = IO::AIO::eventfd [$initval, [$flags]] + $fh = IO::AIO::memfd_create $pathname[, $flags] + + $fh = IO::AIO::timerfd_create $clockid[, $flags] + ($cur_interval, $cur_value) = IO::AIO::timerfd_settime $fh, $flags, $new_interval, $nbw_value + ($cur_interval, $cur_value) = IO::AIO::timerfd_gettime $fh + + $fh = IO::AIO::pidfd_open $pid[, $flags] + $status = IO::AIO::pidfd_send_signal $pidfh, $signal[, $siginfo[, $flags]] + $fh = IO::AIO::pidfd_getfd $pidfh, $targetfd[, $flags] + + $retval = IO::AIO::mount $special, $path, $fstype, $flags = 0, $data = undef + $retval = IO::AIO::umount $path, $flags = 0 + =head2 API NOTES All the C calls are more or less thin wrappers around the syscall @@ -376,9 +415,6 @@ Asynchronously open or create a file and call the callback with a newly created filehandle for the file (or C in case of an error). -The pathname passed to C must be absolute. See API NOTES, above, -for an explanation. - The C<$flags> argument is a bitmask. See the C module for a list. They are the same as used by C. @@ -548,9 +584,6 @@ using C or C<-s _> and other tests (with the exception of C<-B> and C<-T>). -The pathname passed to C must be absolute. See API NOTES, above, -for an explanation. - Currently, the stats are always 64-bit-stats, i.e. instead of returning an error when stat'ing a large file, the results will be silently truncated unless perl itself is compiled with large file support. @@ -944,6 +977,11 @@ aioreq_pri $pri; add $grp aio_open $dst, O_CREAT | O_WRONLY | O_TRUNC, 0200, sub { if (my $dst_fh = $_[0]) { + + # best-effort preallocate + aioreq_pri $pri; + add $grp aio_allocate $dst_fh, IO::AIO::FALLOC_FL_KEEP_SIZE, 0, $stat[7], sub { }; + aioreq_pri $pri; add $grp aio_sendfile $dst_fh, $src_fh, 0, $stat[7], sub { if ($_[0] == $stat[7]) { @@ -1111,13 +1149,69 @@ return $grp->result () if $_[0]; my $now = time; my $hash1 = join ":", (stat _)[0,1,3,7,9]; + my $rdxflags = READDIR_DIRS_FIRST; + + if ((stat _)[3] < 2) { + # at least one non-POSIX filesystem exists + # that returns useful DT_type values: btrfs, + # so optimise for this here by requesting dents + $rdxflags |= READDIR_DENTS; + } # read the directory entries aioreq_pri $pri; - add $grp aio_readdirx $wd, READDIR_DIRS_FIRST, sub { - my $entries = shift + add $grp aio_readdirx $wd, $rdxflags, sub { + my ($entries, $flags) = @_ or return $grp->result (); + if ($rdxflags & READDIR_DENTS) { + # if we requested type values, see if we can use them directly. + + # if there were any DT_UNKNOWN entries then we assume we + # don't know. alternatively, we could assume that if we get + # one DT_DIR, then all directories are indeed marked with + # DT_DIR, but this seems not required for btrfs, and this + # is basically the "btrfs can't get it's act together" code + # branch. + unless ($flags & READDIR_FOUND_UNKNOWN) { + # now we have valid DT_ information for all entries, + # so use it as an optimisation without further stat's. + # they must also all be at the beginning of @$entries + # by now. + + my $dirs; + + if (@$entries) { + for (0 .. $#$entries) { + if ($entries->[$_][1] != DT_DIR) { + # splice out directories + $dirs = [splice @$entries, 0, $_]; + last; + } + } + + # if we didn't find any non-dir, then all entries are dirs + unless ($dirs) { + ($dirs, $entries) = ($entries, []); + } + } else { + # directory is empty, so there are no sbdirs + $dirs = []; + } + + # either splice'd the directories out or the dir was empty. + # convert dents to filenames + $_ = $_->[0] for @$dirs; + $_ = $_->[0] for @$entries; + + return $grp->result ($dirs, $entries); + } + + # cannot use, so return to our old ways + # by pretending we only scanned for names. + $_ = $_->[0] for @$entries; + } + # stat the dir another time aioreq_pri $pri; add $grp aio_stat $wd, sub { @@ -1232,7 +1326,8 @@ other processes), although if you are careful and know what you are doing, you still can. -The following constants are available (missing ones are, as usual C<0>): +The following constants are available and can be used for normal C +and C as well (missing ones are, as usual C<0>): C, @@ -1240,6 +1335,9 @@ C, C, C, C, C, C. +C, C, C, C, C and +C. + C, C, C, C, C. @@ -1257,6 +1355,11 @@ C, C, C, C, C, C, C, C, +C, C, C, C, C, C, +C, C, C, C, C, C, +C, C, C, + + =item aio_sync $callback->($status) Asynchronously call sync and call the callback when finished. @@ -1387,11 +1490,14 @@ =item aio_mlockall $flags, $callback->($status) -Calls the C function with the given C<$flags> (a combination of -C and C). +Calls the C function with the given C<$flags> (a +combination of C, C and +C). On systems that do not implement C, this function returns C<-1> -and sets errno to C. +and sets errno to C. Similarly, flag combinations not supported +by the system result in a return value of C<-1> with errno being set to +C. Note that the corresponding C is synchronous and is documented under L. @@ -1595,7 +1701,7 @@ =item IO::AIO::CWD -This is a compiletime constant (object) that represents the process +This is a compile time constant (object) that represents the process current working directory. Specifying this object as working directory object for a pathname is as if @@ -1977,12 +2083,13 @@ In other words, this setting does not enforce a queue limit, but can be used to make poll functions block if the limit is exceeded. -This is a very bad function to use in interactive programs because it -blocks, and a bad way to reduce concurrency because it is inexact: Better -use an C together with a feed callback. +This is a bad function to use in interactive programs because it blocks, +and a bad way to reduce concurrency because it is inexact. If you need to +issue many requests without being able to call a poll function on demand, +it is better to use an C together with a feed callback. -Its main use is in scripts without an event loop - when you want to stat -a lot of files, you can write something like this: +Its main use is in scripts without an event loop - when you want to stat a +lot of files, you can write something like this: IO::AIO::max_outstanding 32; @@ -1993,10 +2100,11 @@ IO::AIO::flush; -The call to C inside the loop will normally return instantly, but -as soon as more thna C<32> reqeusts are in-flight, it will block until -some requests have been handled. This keeps the loop from pushing a large -number of C requests onto the queue. +The call to C inside the loop will normally return instantly, +allowing the loop to progress, but as soon as more than C<32> requests +are in-flight, it will block until some requests have been handled. This +keeps the loop from pushing a large number of C requests onto +the queue (which, with many paths to stat, can use up a lot of memory). The default value for C is very large, so there is no practical limit on the number of outstanding requests. @@ -2065,7 +2173,7 @@ File birth time is only available when the OS and perl support it (on FreeBSD and NetBSD at the time of this writing, although support is -adaptive, so if your OS/perl gains support, IO::AIO can take avdantage of +adaptive, so if your OS/perl gains support, IO::AIO can take advantage of it). On systems where it isn't available, C<0> is currently returned, but this might change to C in a future version. @@ -2095,11 +2203,11 @@ =item $counter = IO::AIO::st_gen -Returns the generation counter of the file. This is only available on -platforms which have this member in their C (most BSDs -at the time of this writing) and generally only to the root usert. If -unsupported, C<0> is returned, but this might change to C in a -future version. +Returns the generation counter (in practice this is just a random number) +of the file. This is only available on platforms which have this member in +their C (most BSDs at the time of this writing) and generally +only to the root usert. If unsupported, C<0> is returned, but this might +change to C in a future version. =back @@ -2134,9 +2242,39 @@ =over 4 -=item $numfd = IO::AIO::get_fdlimit +=item $retval = IO::AIO::fexecve $fh, $argv, $envp + +A more-or-less direct equivalent to the POSIX C functions, which +allows you to specify the program to be executed via a file descriptor (or +handle). Returns C<-1> and sets errno to C if not available. -This function is I and subject to change. +=item $retval = IO::AIO::mount $special, $path, $fstype, $flags = 0, $data = undef + +Calls the GNU/Linux mount syscall with the given arguments. All except +C<$flags> are strings, and if C<$data> is C, a C will be +passed. + +The following values for C<$flags> are available: + +C, C, C, C, C, +C, C, C, C, +C, C, C, C, C, +C, C, C, C, C, +C, C, C, C, +C, C, C, C, C and +C. + +=item $retval = IO::AIO::umount $path, $flags = 0 + +Invokes the GNU/Linux C or C syscalls. Always calls +C if C<$flags> is C<0>, otherwqise always tries to call +C. + +The following C<$flags> are available: + +C, C, C and C. + +=item $numfd = IO::AIO::get_fdlimit Tries to find the current file descriptor limit and returns it, or C and sets C<$!> in case of an error. The limit is one larger than @@ -2144,8 +2282,6 @@ =item IO::AIO::min_fdlimit [$numfd] -This function is I and subject to change. - Try to increase the current file descriptor limit(s) to at least C<$numfd> by changing the soft or hard file descriptor resource limit. If C<$numfd> is missing, it will try to set a very high limit, although this is not @@ -2249,8 +2385,12 @@ C, C, C, -C or -C. +C, +C, +C, +C, +C or +C. If C<$fh> is C, then a file descriptor of C<-1> is passed. @@ -2297,6 +2437,11 @@ On systems where this call is not supported or is not emulated, this call returns falls and sets C<$!> to C. +=item IO::AIO::mlockall $flags + +Calls the C function, which is like C, +but is blocking. + =item IO::AIO::munlock $scalar, $offset = 0, $length = undef Calls the C function, undoing the effects of a previous @@ -2309,6 +2454,27 @@ On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. +=item $fh = IO::AIO::accept4 $r_fh, $sockaddr, $sockaddr_maxlen, $flags + +Uses the GNU/Linux C syscall, if available, to accept a socket +and return the new file handle on success, or sets C<$!> and returns +C on error. + +The remote name of the new socket will be stored in C<$sockaddr>, which +will be extended to allow for at least C<$sockaddr_maxlen> octets. If the +socket name does not fit into C<$sockaddr_maxlen> octets, this is signaled +by returning a longer string in C<$sockaddr>, which might or might not be +truncated. + +To accept name-less sockets, use C for C<$sockaddr> and C<0> for +C<$sockaddr_maxlen>. + +The main reasons to use this syscall rather than portable C +are that you can specify C and/or C +flags and you can accept name-less sockets by specifying C<0> for +C<$sockaddr_maxlen>, which is sadly not possible with perl's interface to +C. + =item IO::AIO::splice $r_fh, $r_off, $w_fh, $w_off, $length, $flags Calls the GNU/Linux C syscall, if available. If C<$r_off> or @@ -2361,6 +2527,90 @@ my ($rfh, $wfh) = IO::AIO::pipe2 IO::AIO::O_CLOEXEC or die "pipe2: $!\n"; +=item $fh = IO::AIO::memfd_create $pathname[, $flags] + +This is a direct interface to the Linux L system +call. The (unhelpful) default for C<$flags> is C<0>, but your default +should be C. + +On success, the new memfd filehandle is returned, otherwise returns +C. If the memfd_create syscall is missing, fails with C. + +Please refer to L for more info on this call. + +The following C<$flags> values are available: C, +C, C, +C and C. + +Example: create a new memfd. + + my $fh = IO::AIO::memfd_create "somenameforprocfd", IO::AIO::MFD_CLOEXEC + or die "memfd_create: $!\n"; + +=item $fh = IO::AIO::pidfd_open $pid[, $flags] + +This is an interface to the Linux L system call. The +default for C<$flags> is C<0>. + +On success, a new pidfd filehandle is returned (that is already set to +close-on-exec), otherwise returns C. If the syscall is missing, +fails with C. + +Example: open pid 6341 as pidfd. + + my $fh = IO::AIO::pidfd_open 6341 + or die "pidfd_open: $!\n"; + +=item $status = IO::AIO::pidfd_send_signal $pidfh, $signal[, $siginfo[, $flags]] + +This is an interface to the Linux L system call. The +default for C<$siginfo> is C and the default for C<$flags> is C<0>. + +Returns the system call status. If the syscall is missing, fails with +C. + +When specified, C<$siginfo> must be a reference to a hash with one or more +of the following members: + +=over + +=item code - the C member + +=item pid - the C member + +=item uid - the C member + +=item value_int - the C member + +=item value_ptr - the C member, specified as an integer + +=back + +Example: send a SIGKILL to the specified process. + + my $status = IO::AIO::pidfd_send_signal $pidfh, 9, undef + and die "pidfd_send_signal: $!\n"; + +Example: send a SIGKILL to the specified process with extra data. + + my $status = IO::AIO::pidfd_send_signal $pidfh, 9, { code => -1, value_int => 7 } + and die "pidfd_send_signal: $!\n"; + +=item $fh = IO::AIO::pidfd_getfd $pidfh, $targetfd[, $flags] + +This is an interface to the Linux L system call. The default +for C<$flags> is C<0>. + +On success, returns a dup'ed copy of the target file descriptor (specified +as an integer) returned (that is already set to close-on-exec), otherwise +returns C. If the syscall is missing, fails with C. + +Example: get a copy of standard error of another process and print soemthing to it. + + my $errfh = IO::AIO::pidfd_getfd $pidfh, 2 + or die "pidfd_getfd: $!\n"; + print $errfh "stderr\n"; + =item $fh = IO::AIO::eventfd [$initval, [$flags]] This is a direct interface to the Linux L system call. The @@ -2376,16 +2626,17 @@ Example: create a new eventfd filehandle: - $fh = IO::AIO::eventfd 0, IO::AIO::O_CLOEXEC + $fh = IO::AIO::eventfd 0, IO::AIO::EFD_CLOEXEC or die "eventfd: $!\n"; =item $fh = IO::AIO::timerfd_create $clockid[, $flags] -This is a direct interface to the Linux L system call. The -(unhelpful) default for C<$flags> is C<0>. +This is a direct interface to the Linux L system +call. The (unhelpful) default for C<$flags> is C<0>, but your default +should be C. On success, the new timerfd filehandle is returned, otherwise returns -C. If the eventfd syscall is missing, fails with C. +C. If the timerfd_create syscall is missing, fails with C. Please refer to L for more info on this call. @@ -2561,7 +2812,7 @@ =head1 SEE ALSO L for easy integration into event loops, L for a -more natural syntax. +more natural syntax and L for file descriptor passing. =head1 AUTHOR