--- IO-AIO/AIO.xs 2015/06/25 15:47:01 1.235 +++ IO-AIO/AIO.xs 2018/02/20 04:32:59 1.253 @@ -23,7 +23,8 @@ /* the incompetent fool that created musl keeps __linux__, refuses * to implement any linux standard apis, and also has no way to test - * for his broken iplementation. on't complain if this fails for you. + * for his broken iplementation. don't complain to me if this fails + * for you. */ #if __linux__ && (defined __GLIBC__ || defined __UCLIBC__) # include @@ -105,6 +106,17 @@ /*****************************************************************************/ +#include "libeio/config.h" + +#if HAVE_EVENTFD +# include +#endif + +#if HAVE_RLIMITS + #include + #include +#endif + typedef SV SV8; /* byte-sv, used for argument-checking */ typedef int aio_rfd; /* read file desriptor */ typedef int aio_wfd; /* write file descriptor */ @@ -120,7 +132,6 @@ #define EIO_NO_WRAPPERS 1 -#include "libeio/config.h" #include "libeio/eio.h" static int req_invoke (eio_req *req); @@ -166,6 +177,97 @@ /*****************************************************************************/ +#if !_POSIX_MAPPED_FILES +# define mmap(addr,length,prot,flags,fd,offs) EIO_ENOSYS () +# define munmap(addr,length) EIO_ENOSYS () +#endif + +#if !_POSIX_MEMORY_PROTECTION +# define mprotect(addr,len,prot) EIO_ENOSYS () +#endif + +#define FOREIGN_MAGIC PERL_MAGIC_ext + +static int ecb_cold +mmap_free (pTHX_ SV *sv, MAGIC *mg) +{ + int old_errno = errno; + munmap (mg->mg_ptr, (size_t)mg->mg_obj); + errno = old_errno; + + mg->mg_obj = 0; /* just in case */ + + SvREADONLY_off (sv); + + if (SvPVX (sv) != mg->mg_ptr) + croak ("ERROR: IO::AIO::mmap-mapped scalar changed location, detected"); + + SvCUR_set (sv, 0); + SvPVX (sv) = 0; + SvOK_off (sv); + + return 0; +} + +static MGVTBL mmap_vtbl = { + 0, 0, 0, 0, mmap_free +}; + +static int ecb_cold +sysfree_free (pTHX_ SV *sv, MAGIC *mg) +{ + free (mg->mg_ptr); + mg->mg_obj = 0; /* just in case */ + + SvREADONLY_off (sv); + + if (SvPVX (sv) != mg->mg_ptr) + croak ("ERROR: IO::AIO mapped scalar changed location, detected"); + + SvCUR_set (sv, 0); + SvPVX (sv) = 0; + SvOK_off (sv); + + return 0; +} + +static MGVTBL sysfree_vtbl = { + 0, 0, 0, 0, sysfree_free +}; + +/*****************************************************************************/ + +/* helper: set scalar to foreign ptr with custom free */ +static void +sv_set_foreign (SV *sv, const MGVTBL *const vtbl, void *addr, IV length) +{ + sv_force_normal (sv); + + /* we store the length in mg_obj, as namlen is I32 :/ */ + sv_magicext (sv, 0, FOREIGN_MAGIC, vtbl, (char *)addr, 0) + ->mg_obj = (SV *)length; + + SvUPGRADE (sv, SVt_PV); /* nop... */ + + if (SvLEN (sv)) + Safefree (SvPVX (sv)); + + SvPVX (sv) = (char *)addr; + SvCUR_set (sv, length); + SvLEN_set (sv, 0); + SvPOK_only (sv); +} + +static void +sv_clear_foreign (SV *sv) +{ + /* todo: iterate over magic and only free ours, but of course */ + /* the perl5porters will call that (correct) behaviour buggy */ + sv_unmagic (sv, FOREIGN_MAGIC); +} + +/*****************************************************************************/ + static void fiemap (eio_req *req) { @@ -592,6 +694,30 @@ } break; + case EIO_SLURP: + { + if (req->result >= 0) + { + /* if length was originally not known, we steal the malloc'ed memory */ + if (req->flags & EIO_FLAG_PTR2_FREE) + { + req->flags &= ~EIO_FLAG_PTR2_FREE; + sv_set_foreign (req->sv2, &sysfree_vtbl, req->ptr2, req->result); + } + else + { + SvCUR_set (req->sv2, req->result); + *SvEND (req->sv2) = 0; + SvPOK_only (req->sv2); + } + + SvSETMAGIC (req->sv2); + } + + PUSHs (sv_result); + } + break; + case EIO_CUSTOM: if (req->feed == fiemap) { @@ -706,14 +832,14 @@ { int size; - X_LOCK (reslock); - size = res_queue.size; - X_UNLOCK (reslock); + X_LOCK (EIO_POOL->reslock); + size = EIO_POOL->res_queue.size; + X_UNLOCK (EIO_POOL->reslock); if (size) return; - etp_maybe_start_thread (); + etp_maybe_start_thread (EIO_POOL); s_epipe_wait (&respipe); } @@ -747,44 +873,6 @@ /*****************************************************************************/ -#if !_POSIX_MAPPED_FILES -# define mmap(addr,length,prot,flags,fd,offs) EIO_ENOSYS () -# define munmap(addr,length) EIO_ENOSYS () -#endif - -#if !_POSIX_MEMORY_PROTECTION -# define mprotect(addr,len,prot) EIO_ENOSYS () -#endif - -#define MMAP_MAGIC PERL_MAGIC_ext - -static int ecb_cold -mmap_free (pTHX_ SV *sv, MAGIC *mg) -{ - int old_errno = errno; - munmap (mg->mg_ptr, (size_t)mg->mg_obj); - errno = old_errno; - - mg->mg_obj = 0; /* just in case */ - - SvREADONLY_off (sv); - - if (SvPVX (sv) != mg->mg_ptr) - croak ("ERROR: IO::AIO::mmap-mapped scalar changed location, detected"); - - SvCUR_set (sv, 0); - SvPVX (sv) = 0; - SvOK_off (sv); - - return 0; -} - -static MGVTBL mmap_vtbl = { - 0, 0, 0, 0, mmap_free -}; - -/*****************************************************************************/ - static SV * get_cb (SV *cb_sv) { @@ -987,7 +1075,6 @@ const_iv (MAP_ANONYMOUS) /* linuxish */ - const_iv (MAP_HUGETLB) const_iv (MAP_LOCKED) const_iv (MAP_NORESERVE) const_iv (MAP_POPULATE) @@ -997,6 +1084,69 @@ const_iv (MAP_HUGETLB) const_iv (MAP_STACK) + const_iv (F_DUPFD_CLOEXEC) + + const_iv (F_OFD_GETLK) + const_iv (F_OFD_SETLK) + const_iv (F_OFD_GETLKW) + + const_iv (FIFREEZE) + const_iv (FITHAW) + const_iv (FITRIM) + const_iv (FICLONE) + const_iv (FICLONERANGE) + const_iv (FIDEDUPERANGE) + + const_iv (FS_IOC_GETFLAGS) + const_iv (FS_IOC_SETFLAGS) + const_iv (FS_IOC_GETVERSION) + const_iv (FS_IOC_SETVERSION) + const_iv (FS_IOC_FIEMAP) + const_iv (FS_IOC_FSGETXATTR) + const_iv (FS_IOC_FSSETXATTR) + const_iv (FS_IOC_SET_ENCRYPTION_POLICY) + const_iv (FS_IOC_GET_ENCRYPTION_PWSALT) + const_iv (FS_IOC_GET_ENCRYPTION_POLICY) + + const_iv (FS_KEY_DESCRIPTOR_SIZE) + + const_iv (FS_SECRM_FL) + const_iv (FS_UNRM_FL) + const_iv (FS_COMPR_FL) + const_iv (FS_SYNC_FL) + const_iv (FS_IMMUTABLE_FL) + const_iv (FS_APPEND_FL) + const_iv (FS_NODUMP_FL) + const_iv (FS_NOATIME_FL) + const_iv (FS_DIRTY_FL) + const_iv (FS_COMPRBLK_FL) + const_iv (FS_NOCOMP_FL) + const_iv (FS_ENCRYPT_FL) + const_iv (FS_BTREE_FL) + const_iv (FS_INDEX_FL) + const_iv (FS_JOURNAL_DATA_FL) + const_iv (FS_NOTAIL_FL) + const_iv (FS_DIRSYNC_FL) + const_iv (FS_TOPDIR_FL) + const_iv (FS_FL_USER_MODIFIABLE) + + const_iv (FS_XFLAG_REALTIME) + const_iv (FS_XFLAG_PREALLOC) + const_iv (FS_XFLAG_IMMUTABLE) + const_iv (FS_XFLAG_APPEND) + const_iv (FS_XFLAG_SYNC) + const_iv (FS_XFLAG_NOATIME) + const_iv (FS_XFLAG_NODUMP) + const_iv (FS_XFLAG_RTINHERIT) + const_iv (FS_XFLAG_PROJINHERIT) + const_iv (FS_XFLAG_NOSYMLINKS) + const_iv (FS_XFLAG_EXTSIZE) + const_iv (FS_XFLAG_EXTSZINHERIT) + const_iv (FS_XFLAG_NODEFRAG) + const_iv (FS_XFLAG_FILESTREAM) + const_iv (FS_XFLAG_DAX) + const_iv (FS_XFLAG_HASATTR) + const_iv (FIEMAP_FLAG_SYNC) const_iv (FIEMAP_FLAG_XATTR) const_iv (FIEMAP_FLAGS_COMPAT) @@ -1017,6 +1167,10 @@ const_iv (SPLICE_F_MORE) const_iv (SPLICE_F_GIFT) + const_iv (EFD_CLOEXEC) + const_iv (EFD_NONBLOCK) + const_iv (EFD_SEMAPHORE) + /* these are libeio constants, and are independent of gendef0 */ const_eio (SEEK_SET) const_eio (SEEK_CUR) @@ -1039,6 +1193,12 @@ const_eio (FALLOC_FL_PUNCH_HOLE) const_eio (FALLOC_FL_COLLAPSE_RANGE) const_eio (FALLOC_FL_ZERO_RANGE) + const_eio (FALLOC_FL_INSERT_RANGE) + const_eio (FALLOC_FL_UNSHARE_RANGE) + + const_eio (RENAME_NOREPLACE) + const_eio (RENAME_EXCHANGE) + const_eio (RENAME_WHITEOUT) const_eio (READDIR_DENTS) const_eio (READDIR_DIRS_FIRST) @@ -1299,6 +1459,46 @@ } void +aio_ioctl (SV *fh, unsigned long request, SV8 *arg, SV *callback = &PL_sv_undef) + ALIAS: + aio_ioctl = EIO_IOCTL + aio_fcntl = EIO_FCNTL + PPCODE: +{ + int fd = s_fileno_croak (fh, 0); + char *svptr; + + if (SvPOK (arg) || !SvNIOK (arg)) + { + STRLEN svlen; + /* perl uses IOCPARM_LEN for fcntl, so we do, too */ +#ifdef IOCPARM_LEN + STRLEN need = IOCPARM_LEN (request); +#else + STRLEN need = 256; +#endif + + if (svlen < need) + svptr = SvGROW (arg, need); + } + else + svptr = (char *)SvIV (arg); + + { + dREQ; + + req->type = ix; + req->sv1 = newSVsv (fh); + req->int1 = fd; + req->int2 = (long)request; + req->sv2 = SvREFCNT_inc (arg); + req->ptr2 = svptr; + + REQ_SEND; + } +} + +void aio_readlink (SV8 *pathname, SV *callback = &PL_sv_undef) ALIAS: aio_readlink = EIO_READLINK @@ -1368,7 +1568,7 @@ ALIAS: minor = 1 CODE: - RETVAL = ix ? major (dev) : minor (dev); + RETVAL = ix ? minor (dev) : major (dev); OUTPUT: RETVAL @@ -1495,6 +1695,22 @@ } void +aio_rename2 (SV8 *oldpath, SV8 *newpath, int flags = 0, SV *callback = &PL_sv_undef) + PPCODE: +{ + eio_wd wd2 = 0; + dREQ; + + req->type = EIO_RENAME; + req_set_path1 (req, oldpath); + req_set_path (req, newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); + req->int2 = flags; + req->int3 = (long)wd2; + + REQ_SEND; +} + +void aio_mknod (SV8 *pathname, int mode, UV dev, SV *callback = &PL_sv_undef) PPCODE: { @@ -1509,7 +1725,7 @@ } void -aio_mtouch (SV8 *data, IV offset = 0, SV *length = &PL_sv_undef, int flags = 0, SV *callback = &PL_sv_undef) +aio_mtouch (SV8 *data, IV offset = 0, SV *length = &PL_sv_undef, int flags = -1, SV *callback = &PL_sv_undef) ALIAS: aio_mtouch = EIO_MTOUCH aio_msync = EIO_MSYNC @@ -1519,6 +1735,9 @@ char *svptr = SvPVbyte (data, svlen); UV len = SvUV (length); + if (flags < 0) + flags = ix == EIO_MSYNC ? EIO_MS_SYNC : 0; + if (offset < 0) offset += svlen; @@ -1606,6 +1825,44 @@ } void +aio_slurp (SV *pathname, off_t offset, UV length, SV8 *data, SV *callback = &PL_sv_undef) + PPCODE: +{ + char *svptr = 0; + + sv_clear_foreign (data); + + if (length) /* known length, directly read into scalar */ + { + if (!SvPOK (data) || SvLEN (data) >= SvCUR (data)) + svptr = sv_grow (data, length + 1); + else if (SvCUR (data) < length) + croak ("length outside of scalar, and cannot grow"); + else + svptr = SvPVbyte_nolen (data); + } + + { + dREQ; + + req->type = EIO_SLURP; + req_set_path1 (req, pathname); + req->offs = offset; + req->size = length; + req->sv2 = SvREFCNT_inc (data); + req->ptr2 = svptr; + + if (!SvREADONLY (data)) + { + SvREADONLY_on (data); + req->flags |= FLAG_SV2_RO_OFF; + } + + REQ_SEND; + } +} + +void aio_busy (double delay, SV *callback = &PL_sv_undef) PPCODE: { @@ -1749,39 +2006,25 @@ void mmap (SV *scalar, STRLEN length, int prot, int flags, SV *fh = &PL_sv_undef, off_t offset = 0) PPCODE: - sv_unmagic (scalar, MMAP_MAGIC); + sv_clear_foreign (scalar); { int fd = SvOK (fh) ? s_fileno_croak (fh, flags & PROT_WRITE) : -1; void *addr = (void *)mmap (0, length, prot, flags, fd, offset); if (addr == (void *)-1) XSRETURN_NO; - sv_force_normal (scalar); - - /* we store the length in mg_obj, as namlen is I32 :/ */ - sv_magicext (scalar, 0, MMAP_MAGIC, &mmap_vtbl, (char *)addr, 0) - ->mg_obj = (SV *)length; - - SvUPGRADE (scalar, SVt_PV); /* nop... */ + sv_set_foreign (scalar, &mmap_vtbl, addr, length); if (!(prot & PROT_WRITE)) SvREADONLY_on (scalar); - if (SvLEN (scalar)) - Safefree (SvPVX (scalar)); - - SvPVX (scalar) = (char *)addr; - SvCUR_set (scalar, length); - SvLEN_set (scalar, 0); - SvPOK_only (scalar); - XSRETURN_YES; } void munmap (SV *scalar) CODE: - sv_unmagic (scalar, MMAP_MAGIC); + sv_clear_foreign (scalar); int madvise (SV *scalar, STRLEN offset = 0, SV *length = &PL_sv_undef, IV advice_or_prot) @@ -1923,6 +2166,92 @@ } } +void +eventfd (unsigned int initval = 0, int flags = 0) + PPCODE: +{ + int fd; +#if HAVE_EVENTFD + fd = eventfd (initval, flags); +#else + fd = (errno = ENOSYS, -1); +#endif + + XPUSHs (newmortalFH (fd, O_RDWR)); +} + +UV +get_fdlimit () + CODE: +#if HAVE_RLIMITS + struct rlimit rl; + if (0 == getrlimit (RLIMIT_NOFILE, &rl)) + XSRETURN_UV (rl.rlim_cur == RLIM_INFINITY ? (UV)-1 : rl.rlim_cur); +#endif + XSRETURN_UNDEF; + OUTPUT: + RETVAL + +void +min_fdlimit (UV limit = 0x7fffffffU) + CODE: +{ +#if HAVE_RLIMITS + struct rlimit rl; + rlim_t orig_rlim_max; + UV bit; + + if (0 != getrlimit (RLIMIT_NOFILE, &rl)) + goto fail; + + if (rl.rlim_cur == RLIM_INFINITY) + XSRETURN_YES; + + orig_rlim_max = rl.rlim_max == RLIM_INFINITY ? ((rlim_t)0)-1 : rl.rlim_max; + + if (rl.rlim_cur < limit) + { + rl.rlim_cur = limit; + + if (rl.rlim_max < rl.rlim_cur && rl.rlim_max != RLIM_INFINITY) + rl.rlim_max = rl.rlim_cur; + } + + if (0 == setrlimit (RLIMIT_NOFILE, &rl)) + XSRETURN_YES; + + if (errno == EPERM) + { + /* setlimit failed with EPERM - maybe we can't raise the hardlimit, or maybe */ + /* our limit overflows a system-wide limit */ + /* try an adaptive algorithm, but do not lower the hardlimit */ + rl.rlim_max = 0; + for (bit = 0x40000000U; bit; bit >>= 1) + { + rl.rlim_max |= bit; + rl.rlim_cur = rl.rlim_max; + + /* nevr decrease the hard limit */ + if (rl.rlim_max < orig_rlim_max) + break; + + if (0 != setrlimit (RLIMIT_NOFILE, &rl)) + rl.rlim_max &= ~bit; /* too high, remove bit again */ + } + + /* now, raise the soft limit to the max permitted */ + if (0 == getrlimit (RLIMIT_NOFILE, &rl)) + { + rl.rlim_cur = rl.rlim_max; + if (0 == setrlimit (RLIMIT_NOFILE, &rl)) + errno = EPERM; + } + } +#endif + fail: + XSRETURN_UNDEF; +} + void _on_next_submit (SV *cb) CODE: SvREFCNT_dec (on_next_submit);