--- IO-AIO/AIO.pm 2014/07/30 22:00:04 1.249 +++ IO-AIO/AIO.pm 2020/12/29 15:16:27 1.308 @@ -1,6 +1,6 @@ =head1 NAME -IO::AIO - Asynchronous Input/Output +IO::AIO - Asynchronous/Advanced Input/Output =head1 SYNOPSIS @@ -60,6 +60,10 @@ aio_write, so the remaining functionality would have to be implemented using threads anyway. +In addition to asynchronous I/O, this module also exports some rather +arcane interfaces, such as C or linux's C system call, +which is why the C in C can also mean I. + Although the module will work in the presence of other (Perl-) threads, it is currently not reentrant in any way, so use appropriate locking yourself, always call C from within the same thread, or never @@ -96,7 +100,7 @@ print $contents; # exit event loop and program - EV::unloop; + EV::break; }; }; @@ -104,7 +108,7 @@ # check for sockets etc. etc. # process events as long as there are some: - EV::loop; + EV::run; =head1 REQUEST ANATOMY AND LIFETIME @@ -169,18 +173,19 @@ use base 'Exporter'; BEGIN { - our $VERSION = 4.31; + our $VERSION = 4.73; 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 - aio_scandir aio_symlink aio_readlink aio_realpath aio_sync - aio_fsync aio_syncfs aio_fdatasync aio_sync_file_range aio_allocate - aio_pathsync aio_readahead aio_fiemap - aio_rename aio_link aio_move aio_copy aio_group + aio_scandir aio_symlink aio_readlink aio_realpath aio_fcntl aio_ioctl + aio_sync aio_fsync aio_syncfs aio_fdatasync aio_sync_file_range + aio_pathsync aio_readahead aio_fiemap aio_allocate + aio_rename aio_rename2 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 aio_msync aio_mtouch aio_mlock aio_mlockall aio_statvfs + aio_slurp aio_wd); our @EXPORT = (@AIO_REQ, qw(aioreq_pri aioreq_nice)); @@ -189,7 +194,7 @@ nreqs nready npending nthreads max_poll_time max_poll_reqs sendfile fadvise madvise - mmap munmap munlock munlockall); + mmap munmap mremap munlock munlockall); push @AIO_REQ, qw(aio_busy); # not exported @@ -231,6 +236,7 @@ aio_readlink $pathname, $callback->($link) aio_realpath $pathname, $callback->($path) aio_rename $srcpath, $dstpath, $callback->($status) + aio_rename2 $srcpath, $dstpath, $flags, $callback->($status) aio_mkdir $pathname, $mode, $callback->($status) aio_rmdir $pathname, $callback->($status) aio_readdir $pathname, $callback->($entries) @@ -242,13 +248,15 @@ aio_copy $srcpath, $dstpath, $callback->($status) aio_move $srcpath, $dstpath, $callback->($status) aio_rmtree $pathname, $callback->($status) + aio_fcntl $fh, $cmd, $arg, $callback->($status) + aio_ioctl $fh, $request, $buf, $callback->($status) aio_sync $callback->($status) aio_syncfs $fh, $callback->($status) aio_fsync $fh, $callback->($status) aio_fdatasync $fh, $callback->($status) aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status) aio_pathsync $pathname, $callback->($status) - aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) + aio_msync $scalar, $offset = 0, $length = undef, flags = MS_SYNC, $callback->($status) aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status) aio_mlockall $flags, $callback->($status) @@ -272,16 +280,42 @@ IO::AIO::nreqs IO::AIO::nready IO::AIO::npending + 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::mmap $scalar, $length, $prot, $flags[, $fh[, $offset]] IO::AIO::munmap $scalar + IO::AIO::mremap $scalar, $new_length, $flags[, $new_address] IO::AIO::madvise $scalar, $offset, $length, $advice IO::AIO::mprotect $scalar, $offset, $length, $protect 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::memfd_create $pathname[, $flags] + $fh = IO::AIO::eventfd [$initval, [$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 + =head2 API NOTES All the C calls are more or less thin wrappers around the syscall @@ -396,7 +430,7 @@ C, C, C, C, C, C, C, C, C, C, C, -C, C and C. +C, C, C, C, C and C. =item aio_close $fh, $callback->($status) @@ -441,8 +475,8 @@ =item aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) Reads or writes C<$length> bytes from or to the specified C<$fh> and -C<$offset> into the scalar given by C<$data> and offset C<$dataoffset> -and calls the callback without the actual number of bytes read (or -1 on +C<$offset> into the scalar given by C<$data> and offset C<$dataoffset> and +calls the callback with the actual number of bytes transferred (or -1 on error, just like the syscall). C will, like C, shrink or grow the C<$data> scalar to @@ -510,7 +544,7 @@ on many systems, this implementation tries to work around some known bugs in Linux and FreeBSD kernels (probably others, too), but that might fail, so you really really should check the return value of C - -fewre bytes than expected might have been transferred. +fewer bytes than expected might have been transferred. =item aio_readahead $fh,$offset,$length, $callback->($retval) @@ -524,17 +558,18 @@ (off-set+length). C does not read beyond the end of the file. The current file offset of the file is left unchanged. -If that syscall doesn't exist (likely if your OS isn't Linux) it will be -emulated by simply reading the data, which would have a similar effect. +If that syscall doesn't exist (likely if your kernel isn't Linux) it will +be emulated by simply reading the data, which would have a similar effect. =item aio_stat $fh_or_path, $callback->($status) =item aio_lstat $fh, $callback->($status) -Works like perl's C or C in void context. The callback will -be called after the stat and the results will be available using C -or C<-s _> etc... +Works almost exactly like perl's C or C in void context. The +callback will be called after the stat and the results will be available +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. @@ -552,6 +587,9 @@ C, C, C, C, C, C. +To access higher resolution stat timestamps, see L. + Example: Print the length of F: aio_stat "/etc/passwd", sub { @@ -604,97 +642,16 @@ fsid => 1810 } -Here is a (likely partial - send me updates!) list of fsid values used by -Linux - it is safe to hardcode these when C<$^O> is C: - - 0x0000adf5 adfs - 0x0000adff affs - 0x5346414f afs - 0x09041934 anon-inode filesystem - 0x00000187 autofs - 0x42465331 befs - 0x1badface bfs - 0x42494e4d binfmt_misc - 0x9123683e btrfs - 0x0027e0eb cgroupfs - 0xff534d42 cifs - 0x73757245 coda - 0x012ff7b7 coh - 0x28cd3d45 cramfs - 0x453dcd28 cramfs-wend (wrong endianness) - 0x64626720 debugfs - 0x00001373 devfs - 0x00001cd1 devpts - 0x0000f15f ecryptfs - 0x00414a53 efs - 0x0000137d ext - 0x0000ef53 ext2/ext3 - 0x0000ef51 ext2 - 0x00004006 fat - 0x65735546 fuseblk - 0x65735543 fusectl - 0x0bad1dea futexfs - 0x01161970 gfs2 - 0x47504653 gpfs - 0x00004244 hfs - 0xf995e849 hpfs - 0x958458f6 hugetlbfs - 0x2bad1dea inotifyfs - 0x00009660 isofs - 0x000072b6 jffs2 - 0x3153464a jfs - 0x6b414653 k-afs - 0x0bd00bd0 lustre - 0x0000137f minix - 0x0000138f minix 30 char names - 0x00002468 minix v2 - 0x00002478 minix v2 30 char names - 0x00004d5a minix v3 - 0x19800202 mqueue - 0x00004d44 msdos - 0x0000564c novell - 0x00006969 nfs - 0x6e667364 nfsd - 0x00003434 nilfs - 0x5346544e ntfs - 0x00009fa1 openprom - 0x7461636F ocfs2 - 0x00009fa0 proc - 0x6165676c pstorefs - 0x0000002f qnx4 - 0x858458f6 ramfs - 0x52654973 reiserfs - 0x00007275 romfs - 0x67596969 rpc_pipefs - 0x73636673 securityfs - 0xf97cff8c selinux - 0x0000517b smb - 0x534f434b sockfs - 0x73717368 squashfs - 0x62656572 sysfs - 0x012ff7b6 sysv2 - 0x012ff7b5 sysv4 - 0x01021994 tmpfs - 0x15013346 udf - 0x00011954 ufs - 0x54190100 ufs byteswapped - 0x00009fa2 usbdevfs - 0x01021997 v9fs - 0xa501fcf5 vxfs - 0xabba1974 xenfs - 0x012ff7b4 xenix - 0x58465342 xfs - 0x012fd16d xia - =item aio_utime $fh_or_path, $atime, $mtime, $callback->($status) Works like perl's C function (including the special case of $atime and $mtime being undef). Fractional times are supported if the underlying syscalls support them. -When called with a pathname, uses utimes(2) if available, otherwise -utime(2). If called on a file descriptor, uses futimes(2) if available, -otherwise returns ENOSYS, so this is not portable. +When called with a pathname, uses utimensat(2) or utimes(2) if available, +otherwise utime(2). If called on a file descriptor, uses futimens(2) +or futimes(2) if available, otherwise returns ENOSYS, so this is not +portable. Examples: @@ -727,12 +684,18 @@ Allocates or frees disk space according to the C<$mode> argument. See the linux C documentation for details. -C<$mode> can currently be C<0> or C -to allocate space, or C, to deallocate a file range. +C<$mode> is usually C<0> or C to allocate +space, or C, +to deallocate a file range. + +IO::AIO also supports C, to remove a range +(without leaving a hole), C, to zero a range, +C to insert a range and C +to unshare shared blocks (see your L manpage). The file system block size used by C is presumably the -C returned by C. +C returned by C, but different filesystems and filetypes +can dictate other limitations. If C isn't available or cannot be emulated (currently no emulation will be attempted), passes C<-1> and sets C<$!> to C. @@ -801,6 +764,22 @@ of failing, C is called on the absolute path of C<$wd>. +=item aio_rename2 $srcpath, $dstpath, $flags, $callback->($status) + +Basically a version of C with an additional C<$flags> +argument. Calling this with C<$flags=0> is the same as calling +C. + +Non-zero flags are currently only supported on GNU/Linux systems that +support renameat2. Other systems fail with C in this case. + +The following constants are available (missing ones are, as usual C<0>), +see renameat2(2) for details: + +C, C +and C. + + =item aio_mkdir $pathname, $mode, $callback->($status) Asynchronously mkdir (create) a directory and call the callback with @@ -841,10 +820,10 @@ =item IO::AIO::READDIR_DENTS -When this flag is off, then the callback gets an arrayref consisting of -names only (as with C), otherwise it gets an arrayref with -C<[$name, $type, $inode]> arrayrefs, each describing a single directory -entry in more detail. +Normally the callback gets an arrayref consisting of names only (as +with C). If this flag is set, then the callback gets an +arrayref with C<[$name, $type, $inode]> arrayrefs, each describing a +single directory entry in more detail: C<$name> is the name of the entry. @@ -854,9 +833,9 @@ C, C, C, C, C. -C means just that: readdir does not know. If you need to -know, you have to run stat yourself. Also, for speed reasons, the C<$type> -scalars are read-only: you can not modify them. +C means just that: readdir does not know. If you need +to know, you have to run stat yourself. Also, for speed/memory reasons, +the C<$type> scalars are read-only: you must not modify them. C<$inode> is the inode number (which might not be exact on systems with 64 bit inode numbers and 32 bit perls). This field has unspecified content on @@ -877,12 +856,14 @@ =item IO::AIO::READDIR_STAT_ORDER When this flag is set, then the names will be returned in an order -suitable for stat()'ing each one. That is, when you plan to stat() -all files in the given directory, then the returned order will likely -be fastest. - -If both this flag and C are specified, then -the likely dirs come first, resulting in a less optimal stat order. +suitable for stat()'ing each one. That is, when you plan to stat() most or +all files in the given directory, then the returned order will likely be +faster. + +If both this flag and C are specified, +then the likely dirs come first, resulting in a less optimal stat order +for stat'ing all entries, but likely a more optimal order for finding +subdirectories. =item IO::AIO::READDIR_FOUND_UNKNOWN @@ -894,11 +875,42 @@ =back +=item aio_slurp $pathname, $offset, $length, $data, $callback->($status) + +Opens, reads and closes the given file. The data is put into C<$data>, +which is resized as required. + +If C<$offset> is negative, then it is counted from the end of the file. + +If C<$length> is zero, then the remaining length of the file is +used. Also, in this case, the same limitations to modifying C<$data> apply +as when IO::AIO::mmap is used, i.e. it must only be modified in-place +with C. If the size of the file is known, specifying a non-zero +C<$length> results in a performance advantage. + +This request is similar to the older C request, but since it is +a single request, it might be more efficient to use. + +Example: load F into C<$passwd>. + + my $passwd; + aio_slurp "/etc/passwd", 0, 0, $passwd, sub { + $_[0] >= 0 + or die "/etc/passwd: $!\n"; + + printf "/etc/passwd is %d bytes long, and contains:\n", length $passwd; + print $passwd; + }; + IO::AIO::flush; + + =item aio_load $pathname, $data, $callback->($status) This is a composite request that tries to fully load the given file into memory. Status is the same as with aio_read. +Using C might be more efficient, as it is a single request. + =cut sub aio_load($$;$) { @@ -928,6 +940,8 @@ destination) from C<$srcpath> to C<$dstpath> and call the callback with a status of C<0> (ok) or C<-1> (error, see C<$!>). +Existing destination files will be truncated. + This is a composite request that creates the destination file with mode 0200 and copies the contents of the source file into it using C, followed by restoring atime, mtime, access mode and @@ -1046,7 +1060,7 @@ names, directories you can recurse into (directories), and ones you cannot recurse into (everything else, including symlinks to directories). -C is a composite request that creates of many sub requests_ +C is a composite request that generates many sub requests. C<$maxreq> specifies the maximum number of outstanding aio requests that this function generates. If it is C<< <= 0 >>, then a suitable default will be chosen (currently 4). @@ -1120,13 +1134,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 { @@ -1222,6 +1292,54 @@ $grp } +=item aio_fcntl $fh, $cmd, $arg, $callback->($status) + +=item aio_ioctl $fh, $request, $buf, $callback->($status) + +These work just like the C and C built-in functions, except +they execute asynchronously and pass the return value to the callback. + +Both calls can be used for a lot of things, some of which make more sense +to run asynchronously in their own thread, while some others make less +sense. For example, calls that block waiting for external events, such +as locking, will also lock down an I/O thread while it is waiting, which +can deadlock the whole I/O system. At the same time, there might be no +alternative to using a thread to wait. + +So in general, you should only use these calls for things that do +(filesystem) I/O, not for things that wait for other events (network, +other processes), although if you are careful and know what you are doing, +you still can. + +The following constants are available and can be used for normal C +and C as well (missing ones are, as usual C<0>): + +C, + +C, C, C, + +C, C, C, C, C, C. + +C, C, C, C, C and +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, 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. @@ -1299,7 +1417,7 @@ $grp } -=item aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) +=item aio_msync $scalar, $offset = 0, $length = undef, flags = MS_SYNC, $callback->($status) This is a rather advanced IO::AIO call, which only works on mmap(2)ed scalars (see the C function, although it also works on data @@ -1311,8 +1429,8 @@ area starting at C<$offset> in the string and ending C<$length> bytes later. If C<$length> is negative, counts from the end, and if C<$length> is C, then it goes till the end of the string. The flags can be -a combination of C, C and -C. +either C or C, plus an optional +C. =item aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) @@ -1352,11 +1470,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. @@ -1405,10 +1526,11 @@ C, C or C. -At the time of this writing (Linux 3.2), this requets is unreliable unless +At the time of this writing (Linux 3.2), this request is unreliable unless C<$count> is C, as the kernel has all sorts of bugs preventing -it to return all extents of a range for files with large number of -extents. The code works around all these issues if C<$count> is undef. +it to return all extents of a range for files with a large number of +extents. The code (only) works around all these issues if C<$count> is +C. =item aio_group $callback->(...) @@ -1502,9 +1624,9 @@ }; }; -That C is a request and not a normal function shows that creating -an IO::AIO::WD object is itself a potentially blocking operation, which is -why it is done asynchronously. +The fact that C is a request and not a normal function shows that +creating an IO::AIO::WD object is itself a potentially blocking operation, +which is why it is done asynchronously. To stat the directory obtained with C above, one could write either of the following three request calls: @@ -1531,8 +1653,8 @@ nowhere at all), while the directory fd, if available on the system, will still point to the original directory. Most functions accepting a pathname will use the directory fd on newer systems, and the string on -older systems. Some functions (such as realpath) will always rely on the -string form of the pathname. +older systems. Some functions (such as C) will always rely on +the string form of the pathname. So this functionality is mainly useful to get some protection against C, to easily get an absolute path out of a relative path for future @@ -1559,7 +1681,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 @@ -1750,6 +1872,7 @@ =back + =head2 SUPPORT FUNCTIONS =head3 EVENT PROCESSING AND EVENT LOOP INTEGRATION @@ -1824,6 +1947,16 @@ IO::AIO::poll_wait, IO::AIO::poll_cb while IO::AIO::nreqs; +This function can be useful at program aborts, to make sure outstanding +I/O has been done (C uses an C block which already calls +this function on normal exits), or when you are merely using C +for its more advanced functions, rather than for async I/O, e.g.: + + my ($dirs, $nondirs); + IO::AIO::aio_scandir "/tmp", 0, sub { ($dirs, $nondirs) = @_ }; + IO::AIO::flush; + # $dirs, $nondirs are now set + =item IO::AIO::max_poll_reqs $nreqs =item IO::AIO::max_poll_time $seconds @@ -1859,6 +1992,7 @@ =back + =head3 CONTROLLING THE NUMBER OF THREADS =over @@ -1934,7 +2068,7 @@ 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 somehting like this: +a lot of files, you can write something like this: IO::AIO::max_outstanding 32; @@ -1955,6 +2089,7 @@ =back + =head3 STATISTICAL INFORMATION =over @@ -1981,6 +2116,101 @@ =back + +=head3 SUBSECOND STAT TIME ACCESS + +Both C/C and perl's C/C functions can +generally find access/modification and change times with subsecond time +accuracy of the system supports it, but perl's built-in functions only +return the integer part. + +The following functions return the timestamps of the most recent +stat with subsecond precision on most systems and work both after +C/C and perl's C/C calls. Their return +value is only meaningful after a successful C/C call, or +during/after a successful C/C callback. + +This is similar to the L C functions, but can return +full resolution without rounding and work with standard perl C, +alleviating the need to call the special C functions, which +do not act like their perl counterparts. + +On operating systems or file systems where subsecond time resolution is +not supported or could not be detected, a fractional part of C<0> is +returned, so it is always safe to call these functions. + +=over 4 + +=item $seconds = IO::AIO::st_atime, IO::AIO::st_mtime, IO::AIO::st_ctime, IO::AIO::st_btime + +Return the access, modication, change or birth time, respectively, +including fractional part. Due to the limited precision of floating point, +the accuracy on most platforms is only a bit better than milliseconds +for times around now - see the I function family, below, for full +accuracy. + +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 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. + +=item ($atime, $mtime, $ctime, $btime, ...) = IO::AIO::st_xtime + +Returns access, modification, change and birth time all in one go, and +maybe more times in the future version. + +=item $nanoseconds = IO::AIO::st_atimensec, IO::AIO::st_mtimensec, IO::AIO::st_ctimensec, IO::AIO::st_btimensec + +Return the fractional access, modifcation, change or birth time, in nanoseconds, +as an integer in the range C<0> to C<999999999>. + +Note that no accessors are provided for access, modification and +change times - you need to get those from C if required (C and so on will I generally give you the correct +value). + +=item $seconds = IO::AIO::st_btimesec + +The (integral) seconds part of the file birth time, if available. + +=item ($atime, $mtime, $ctime, $btime, ...) = IO::AIO::st_xtimensec + +Like the functions above, but returns all four times in one go (and maybe +more in future versions). + +=item $counter = IO::AIO::st_gen + +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 + +Example: print the high resolution modification time of F, using +C, and C. + + if (stat "/etc") { + printf "stat(/etc) mtime: %f\n", IO::AIO::st_mtime; + } + + IO::AIO::aio_stat "/etc", sub { + $_[0] + and return; + + printf "aio_stat(/etc) mtime: %d.%09d\n", (stat _)[9], IO::AIO::st_mtimensec; + }; + + IO::AIO::flush; + +Output of the awbove on my system, showing reduced and full accuracy: + + stat(/etc) mtime: 1534043702.020808 + aio_stat(/etc) mtime: 1534043702.020807792 + + =head3 MISCELLANEOUS FUNCTIONS IO::AIO implements some functions that are useful when you want to use @@ -1990,6 +2220,27 @@ =over 4 +=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 +the highest valid file descriptor number. + +=item IO::AIO::min_fdlimit [$numfd] + +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 +recommended when you know the actual minimum that you require. + +If the limit cannot be raised enough, the function makes a best-effort +attempt to increase the limit as much as possible, using various +tricks, while still failing. You can query the resulting limit using +C. + +If an error occurs, returns C and sets C<$!>, otherwise returns +true. + =item IO::AIO::sendfile $ofh, $ifh, $offset, $count Calls the C function, which is like C, @@ -2015,7 +2266,12 @@ Simply calls the C function (see its manpage for details). The following advice constants are available: C, C, -C, C, C. +C, C, +C. + +If C<$offset> is negative, counts from the end. If C<$length> is negative, +the remaining length of the C<$scalar> is used. If possible, C<$length> +will be reduced to fit into the C<$scalar>. On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. @@ -2027,6 +2283,10 @@ constants are available: C, C, C, C. +If C<$offset> is negative, counts from the end. If C<$length> is negative, +the remaining length of the C<$scalar> is used. If possible, C<$length> +will be reduced to fit into the C<$scalar>. + On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. @@ -2036,15 +2296,19 @@ given C<$scalar>, which will act like a string scalar. Returns true on success, and false otherwise. -The only operations allowed on the scalar are C/C that don't -change the string length, and most read-only operations such as copying it -or searching it with regexes and so on. +The scalar must exist, but its contents do not matter - this means you +cannot use a nonexistant array or hash element. When in doubt, C +the scalar first. + +The only operations allowed on the mmapped scalar are C/C, +which don't change the string length, and most read-only operations such +as copying it or searching it with regexes and so on. Anything else is unsafe and will, at best, result in memory leaks. The memory map associated with the C<$scalar> is automatically removed -when the C<$scalar> is destroyed, or when the C or -C functions are called. +when the C<$scalar> is undef'd or destroyed, or when the C +or C functions are called on it. This calls the C(2) function internally. See your system's manual page for details on the C<$length>, C<$prot> and C<$flags> parameters. @@ -2055,13 +2319,20 @@ C<$prot> is a combination of C, C, C and/or C, -C<$flags> can be a combination of C or -C, or a number of system-specific flags (when -not available, the are defined as 0): C -(which is set to C if your system only provides this -constant), C, C, -C, C or -C +C<$flags> can be a combination of +C or +C, +or a number of system-specific flags (when not available, the are C<0>): +C (which is set to C if your system only provides this constant), +C, +C, +C, +C, +C, +C, +C, +C or +C. If C<$fh> is C, then a file descriptor of C<-1> is passed. @@ -2085,6 +2356,34 @@ Removes a previous mmap and undefines the C<$scalar>. +=item IO::AIO::mremap $scalar, $new_length, $flags = MREMAP_MAYMOVE[, $new_address = 0] + +Calls the Linux-specific mremap(2) system call. The C<$scalar> must have +been mapped by C, and C<$flags> must currently either be +C<0> or C. + +Returns true if successful, and false otherwise. If the underlying mmapped +region has changed address, then the true value has the numerical value +C<1>, otherwise it has the numerical value C<0>: + + my $success = IO::AIO::mremap $mmapped, 8192, IO::AIO::MREMAP_MAYMOVE + or die "mremap: $!"; + + if ($success*1) { + warn "scalar has chanegd address in memory\n"; + } + +C and the C<$new_address> argument are currently +implemented, but not supported and might go away in a future version. + +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 @@ -2097,6 +2396,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 @@ -2124,6 +2444,195 @@ C<-1>/C everywhere else. If anybody knows how to influence pipe buffer size on other systems, drop me a note. +=item ($rfh, $wfh) = IO::AIO::pipe2 [$flags] + +This is a direct interface to the Linux L system call. If +C<$flags> is missing or C<0>, then this should be the same as a call to +perl's built-in C function and create a new pipe, and works on +systems that lack the pipe2 syscall. On win32, this case invokes C<_pipe +(..., 4096, O_BINARY)>. + +If C<$flags> is non-zero, it tries to invoke the pipe2 system call with +the given flags (Linux 2.6.27, glibc 2.9). + +On success, the read and write file handles are returned. + +On error, nothing will be returned. If the pipe2 syscall is missing and +C<$flags> is non-zero, fails with C. + +Please refer to L for more info on the C<$flags>, but at the +time of this writing, C, C and +C (Linux 3.4, for packet-based pipes) were supported. + +Example: create a pipe race-free w.r.t. threads and fork: + + 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 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 +(unhelpful) defaults for C<$initval> and C<$flags> are C<0> for both. + +On success, the new eventfd filehandle is returned, otherwise returns +C. If the eventfd syscall is missing, fails with C. + +Please refer to L for more info on this call. + +The following symbol flag values are available: C, +C and C (Linux 2.6.30). + +Example: create a new eventfd filehandle: + + $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>, but your default +should be C. + +On success, the new timerfd filehandle is returned, otherwise returns +C. If the timerfd_create syscall is missing, fails with C. + +Please refer to L for more info on this call. + +The following C<$clockid> values are +available: C, C +C (Linux 3.15) +C (Linux 3.11) and +C (Linux 3.11). + +The following C<$flags> values are available (Linux +2.6.27): C and C. + +Example: create a new timerfd and set it to one-second repeated alarms, +then wait for two alarms: + + my $fh = IO::AIO::timerfd_create IO::AIO::CLOCK_BOOTTIME, IO::AIO::TFD_CLOEXEC + or die "timerfd_create: $!\n"; + + defined IO::AIO::timerfd_settime $fh, 0, 1, 1 + or die "timerfd_settime: $!\n"; + + for (1..2) { + 8 == sysread $fh, my $buf, 8 + or die "timerfd read failure\n"; + + printf "number of expirations (likely 1): %d\n", + unpack "Q", $buf; + } + +=item ($cur_interval, $cur_value) = IO::AIO::timerfd_settime $fh, $flags, $new_interval, $nbw_value + +This is a direct interface to the Linux L system +call. Please refer to its manpage for more info on this call. + +The new itimerspec is specified using two (possibly fractional) second +values, C<$new_interval> and C<$new_value>). + +On success, the current interval and value are returned (as per +C). On failure, the empty list is returned. + +The following C<$flags> values are +available: C and +C. + +See C for a full example. + +=item ($cur_interval, $cur_value) = IO::AIO::timerfd_gettime $fh + +This is a direct interface to the Linux L system +call. Please refer to its manpage for more info on this call. + +On success, returns the current values of interval and value for the given +timerfd (as potentially fractional second values). On failure, the empty +list is returned. + =back =cut @@ -2198,6 +2707,15 @@ =back +=head2 LINUX-SPECIFIC CALLS + +When a call is documented as "linux-specific" then this means it +originated on GNU/Linux. C will usually try to autodetect the +availability and compatibility of such calls regardless of the platform +it is compiled on, so platforms such as FreeBSD which often implement +these calls will work. When in doubt, call them and see if they fail wth +C. + =head2 MEMORY USAGE Per-request usage: @@ -2219,12 +2737,23 @@ =head1 KNOWN BUGS -Known bugs will be fixed in the next release. +Known bugs will be fixed in the next release :) + +=head1 KNOWN ISSUES + +Calls that try to "import" foreign memory areas (such as C +or C) do not work with generic lvalues, such as +non-created hash slots or other scalars I didn't think of. It's best to +avoid such and either use scalar variables or making sure that the scalar +exists (e.g. by storing C) and isn't "funny" (e.g. tied). + +I am not sure anything can be done about this, so this is considered a +known issue, rather than a bug. =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