--- IO-AIO/AIO.xs 2018/08/25 19:25:32 1.267 +++ IO-AIO/AIO.xs 2020/12/29 15:28:02 1.287 @@ -5,6 +5,7 @@ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" +#include "perliol.h" #if !defined mg_findext # define mg_findext(sv,type,vtbl) mg_find (sv, type) @@ -20,16 +21,6 @@ #include #include -#if HAVE_SYS_MKDEV_H -# include -#elif HAVE_SYS_SYSMACROS_H -# include -#endif - -#if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES -# include -#endif - /* 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. don't complain to me if this fails @@ -95,6 +86,7 @@ #include #include + #include #include #include #include @@ -118,6 +110,20 @@ #include "config.h" +#if HAVE_SYS_MKDEV_H +# include +#elif HAVE_SYS_SYSMACROS_H +# include +#endif + +#if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES +# include +#endif + +#if HAVE_SYS_UIO_H +# include +#endif + #if HAVE_ST_XTIMENSEC # define ATIMENSEC PL_statcache.st_atimensec # define MTIMENSEC PL_statcache.st_mtimensec @@ -223,6 +229,12 @@ # define PAGESIZE sysconf (_SC_PAGESIZE) #endif +#if HAVE_SYSCALL +#include +#else +# define syscall(nr,...) (errno = ENOSYS, -1) +#endif + /*****************************************************************************/ #if !_POSIX_MAPPED_FILES @@ -290,6 +302,7 @@ /*****************************************************************************/ /* helper: set scalar to foreign ptr with custom free */ +ecb_noinline static void sv_set_foreign (SV *sv, const MGVTBL *const vtbl, void *addr, IV length) { @@ -340,7 +353,7 @@ req->flags |= EIO_FLAG_PTR1_FREE; /* heuristic: start with 512 bytes (8 extents), and if that isn't enough, */ - /* increase in 3.5kb steps */ + /* increase in fixed steps */ if (count < 0) count = 8; @@ -403,11 +416,11 @@ { struct fiemap_extent *e = incmap->fm_extents + count; - if (e->fe_logical + e->fe_length >= end_offset) - goto done; - fiemap->fm_extents [fiemap->fm_mapped_extents++] = *e; + if (e->fe_logical >= end_offset) + goto done; + if (e->fe_flags & FIEMAP_EXTENT_LAST) goto done; @@ -426,6 +439,15 @@ static int close_fd; /* dummy fd to close fds via dup2 */ +#if HAVE_STATX +static struct statx stx; +#define statx_offsetof(member) offsetof (struct statx, member) +#define eio__statx statx +#else +#define statx_offsetof(member) 0 +#define eio__statx(dir,path,flags,mask,stx) EIO_ENOSYS() +#endif + enum { FLAG_SV2_RO_OFF = 0x40, /* data was set readonly */ }; @@ -458,6 +480,7 @@ } /* must be called at most once */ +ecb_noinline static SV * req_sv (aio_req req, HV *stash) { @@ -476,6 +499,7 @@ return sv_bless (newRV_noinc (newSViv ((intptr_t)wd)), aio_wd_stash); } +ecb_noinline static aio_req SvAIO_REQ (SV *sv) { @@ -548,6 +572,7 @@ } } +ecb_noinline static void req_submit (eio_req *req) { @@ -818,6 +843,12 @@ PUSHs (sv_result); break; +#if 0 + case EIO_CLOSE: + PerlIOUnix_refcnt_dec (req->int1); + break; +#endif + case EIO_DUP2: /* EIO_DUP2 actually means aio_close(), so fudge result value */ if (req->result > 0) SvIV_set (sv_result, 0); @@ -878,7 +909,8 @@ eio_grp_cancel (grp); } -static void ecb_cold +ecb_cold +static void create_respipe (void) { if (s_epipe_renew (&respipe)) @@ -922,7 +954,8 @@ } } -static void ecb_cold +ecb_cold +static void reinit (void) { create_respipe (); @@ -940,6 +973,7 @@ return SvOK (cb_sv) ? s_get_cv_croak (cb_sv) : 0; } +ecb_noinline static aio_req ecb_noinline dreq (SV *callback) { @@ -971,8 +1005,10 @@ if (GIMME_V != G_VOID) \ XPUSHs (req_sv (req, aio_req_stash)); -ecb_inline void -req_set_path (aio_req req, SV *path, SV **wdsv, SV **pathsv, eio_wd *wd, void **ptr) +/* *wdsv, *pathsv, *wd and *ptr must be 0-initialized */ +ecb_inline +void +req_set_path (SV *path, SV **wdsv, SV **pathsv, eio_wd *wd, void **ptr) { if (expect_false (SvROK (path))) { @@ -1007,13 +1043,15 @@ *ptr = SvPVbyte_nolen (*pathsv); } -static void ecb_noinline +ecb_noinline +static void req_set_path1 (aio_req req, SV *path) { - req_set_path (req, path, &req->sv1, &req->sv3, &req->wd, &req->ptr1); + req_set_path (path, &req->sv1, &req->sv3, &req->wd, &req->ptr1); } -static void ecb_noinline +ecb_noinline +static void req_set_fh_or_path (aio_req req, int type_path, int type_fh, SV *fh_or_path) { SV *rv = SvROK (fh_or_path) ? SvRV (fh_or_path) : fh_or_path; @@ -1166,11 +1204,18 @@ const_iv (MREMAP_MAYMOVE) const_iv (MREMAP_FIXED) - const_iv (F_DUPFD_CLOEXEC) - const_iv (MSG_CMSG_CLOEXEC) const_iv (SOCK_CLOEXEC) + const_iv (F_DUPFD_CLOEXEC) + + const_iv (F_ADD_SEALS) + const_iv (F_GET_SEALS) + const_iv (F_SEAL_SEAL) + const_iv (F_SEAL_SHRINK) + const_iv (F_SEAL_GROW) + const_iv (F_SEAL_WRITE) + const_iv (F_OFD_GETLK) const_iv (F_OFD_SETLK) const_iv (F_OFD_GETLKW) @@ -1256,6 +1301,10 @@ const_iv (EFD_NONBLOCK) const_iv (EFD_SEMAPHORE) + const_iv (MFD_CLOEXEC) + const_iv (MFD_ALLOW_SEALING) + const_iv (MFD_HUGETLB) + const_iv (CLOCK_REALTIME) const_iv (CLOCK_MONOTONIC) const_iv (CLOCK_BOOTTIME) @@ -1268,6 +1317,62 @@ const_iv (TFD_TIMER_ABSTIME) const_iv (TFD_TIMER_CANCEL_ON_SET) + const_iv (STATX_TYPE) + const_iv (STATX_MODE) + const_iv (STATX_NLINK) + const_iv (STATX_UID) + const_iv (STATX_GID) + const_iv (STATX_ATIME) + const_iv (STATX_MTIME) + const_iv (STATX_CTIME) + const_iv (STATX_INO) + const_iv (STATX_SIZE) + const_iv (STATX_BLOCKS) + const_iv (STATX_BASIC_STATS) + const_iv (STATX_ALL) + const_iv (STATX_BTIME) + const_iv (STATX_ATTR_COMPRESSED) + const_iv (STATX_ATTR_IMMUTABLE) + const_iv (STATX_ATTR_APPEND) + const_iv (STATX_ATTR_NODUMP) + const_iv (STATX_ATTR_ENCRYPTED) + const_iv (STATX_ATTR_AUTOMOUNT) + + const_iv (AT_FDCWD) + const_iv (AT_SYMLINK_NOFOLLOW) + const_iv (AT_EACCESS) + const_iv (AT_REMOVEDIR) + const_iv (AT_SYMLINK_FOLLOW) + const_iv (AT_NO_AUTOMOUNT) + const_iv (AT_EMPTY_PATH) + const_iv (AT_STATX_SYNC_TYPE) + const_iv (AT_STATX_AS_STAT) + const_iv (AT_STATX_FORCE_SYNC) + const_iv (AT_STATX_DONT_SYNC) + const_iv (AT_RECURSIVE) + + const_iv (OPEN_TREE_CLONE) + + const_iv (FSOPEN_CLOEXEC) + + const_iv (FSPICK_CLOEXEC) + const_iv (FSPICK_SYMLINK_NOFOLLOW) + const_iv (FSPICK_NO_AUTOMOUNT) + const_iv (FSPICK_EMPTY_PATH) + + const_iv (MOVE_MOUNT_F_SYMLINKS) + const_iv (MOVE_MOUNT_F_AUTOMOUNTS) + const_iv (MOVE_MOUNT_F_EMPTY_PATH) + const_iv (MOVE_MOUNT_T_SYMLINKS) + const_iv (MOVE_MOUNT_T_AUTOMOUNTS) + const_iv (MOVE_MOUNT_T_EMPTY_PATH) + + /* waitid */ + const_iv (P_PID) + const_iv (P_PIDFD) + const_iv (P_PGID) + const_iv (P_ALL) + /* these are libeio constants, and are independent of gendef0 */ const_eio (SEEK_SET) const_eio (SEEK_CUR) @@ -1275,6 +1380,7 @@ const_eio (MCL_FUTURE) const_eio (MCL_CURRENT) + const_eio (MCL_ONFAULT) const_eio (MS_ASYNC) const_eio (MS_INVALIDATE) @@ -1474,11 +1580,35 @@ { int fd = s_fileno_croak (fh, 0); dREQ; +#if 0 + /* partially duplicate logic in s_fileno */ + SvGETMAGIC (fh); - req->type = EIO_DUP2; - req->int1 = close_fd; - req->sv2 = newSVsv (fh); - req->int2 = fd; + if (SvROK (fh)) + { + fh = SvRV (fh); + SvGETMAGIC (fh); + } + + if (SvTYPE (fh) == SVt_PVGV) + { + /* perl filehandle */ + PerlIOUnix_refcnt_inc (fd); + do_close ((GV *)fh, 1); + + req->type = EIO_CLOSE; + req->int1 = fd; + /*req->sv2 = newSVsv (fh);*/ /* since we stole the fd, no need to keep the fh */ + } + else +#endif + { + /* fd number */ + req->type = EIO_DUP2; + req->int1 = close_fd; + req->sv2 = newSVsv (fh); + req->int2 = fd; + } REQ_SEND; } @@ -1818,7 +1948,7 @@ req->type = ix; req_set_path1 (req, oldpath); - req_set_path (req, newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); + req_set_path (newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); req->int3 = (long)wd2; REQ_SEND; @@ -1833,7 +1963,7 @@ req->type = EIO_RENAME; req_set_path1 (req, oldpath); - req_set_path (req, newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); + req_set_path (newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); req->int2 = flags; req->int3 = (long)wd2; @@ -2246,6 +2376,14 @@ RETVAL int +mlockall (int flags) + PROTOTYPE: $; + CODE: + RETVAL = eio_mlockall_sync (flags); + OUTPUT: + RETVAL + +int munlockall () CODE: #if _POSIX_MEMLOCK @@ -2257,6 +2395,184 @@ RETVAL int +statx (SV8 *pathname, int flags, UV mask) + CODE: +{ + /* undocumented, and might go away, and anyway, should use eio_statx */ + SV *wdsv = 0; + SV *pathsv = 0; + eio_wd wd = EIO_CWD; + void *ptr; + int res; + + req_set_path (pathname, &wdsv, &pathsv, &wd, &ptr); + RETVAL = eio__statx (!wd || wd->fd == EIO_CWD ? AT_FDCWD : wd->fd, ptr, flags, mask & STATX_ALL, &stx); + + SvREFCNT_dec (pathsv); + SvREFCNT_dec (wdsv); +} + OUTPUT: + RETVAL + +U32 +stx_mode () + PROTOTYPE: + CODE: +#if HAVE_STATX + RETVAL = stx.stx_mode; +#else + XSRETURN_UNDEF; +#endif + OUTPUT: + RETVAL + +#define STATX_OFFSET_mask statx_offsetof (stx_mask) +#define STATX_OFFSET_blksize statx_offsetof (stx_blksize) +#define STATX_OFFSET_nlink statx_offsetof (stx_nlink) +#define STATX_OFFSET_uid statx_offsetof (stx_uid) +#define STATX_OFFSET_gid statx_offsetof (stx_gid) +#define STATX_OFFSET_rdev_major statx_offsetof (stx_rdev_major) +#define STATX_OFFSET_rdev_minor statx_offsetof (stx_rdev_minor) +#define STATX_OFFSET_dev_major statx_offsetof (stx_dev_major) +#define STATX_OFFSET_dev_minor statx_offsetof (stx_dev_minor) +#define STATX_OFFSET_attributes statx_offsetof (stx_attributes) +#define STATX_OFFSET_ino statx_offsetof (stx_ino) +#define STATX_OFFSET_size statx_offsetof (stx_size) +#define STATX_OFFSET_blocks statx_offsetof (stx_blocks) +#define STATX_OFFSET_attributes_mask statx_offsetof (stx_attributes_mask) +#define STATX_OFFSET_atime statx_offsetof (stx_atime) +#define STATX_OFFSET_btime statx_offsetof (stx_btime) +#define STATX_OFFSET_ctime statx_offsetof (stx_ctime) +#define STATX_OFFSET_mtime statx_offsetof (stx_mtime) + +U32 +stx_mask () + PROTOTYPE: + ALIAS: + stx_mask = STATX_OFFSET_mask + stx_blksize = STATX_OFFSET_blksize + stx_nlink = STATX_OFFSET_nlink + stx_uid = STATX_OFFSET_uid + stx_gid = STATX_OFFSET_gid + stx_rdev_major = STATX_OFFSET_rdev_major + stx_rdev_minor = STATX_OFFSET_rdev_minor + stx_dev_major = STATX_OFFSET_dev_major + stx_dev_minor = STATX_OFFSET_dev_minor + CODE: +#if HAVE_STATX + RETVAL = *(__u32 *)((char *)&stx + ix); +#else + XSRETURN_UNDEF; +#endif + OUTPUT: + RETVAL + +VAL64 +stx_attributes () + PROTOTYPE: + ALIAS: + stx_attributes = STATX_OFFSET_attributes + stx_ino = STATX_OFFSET_ino + stx_size = STATX_OFFSET_size + stx_blocks = STATX_OFFSET_blocks + stx_attributes_mask = STATX_OFFSET_attributes_mask + CODE: +#if HAVE_STATX + RETVAL = *(__u64 *)((char *)&stx + ix); +#else + XSRETURN_UNDEF; +#endif + OUTPUT: + RETVAL + +NV +stx_atime () + PROTOTYPE: + ALIAS: + stx_atime = STATX_OFFSET_atime + stx_btime = STATX_OFFSET_btime + stx_ctime = STATX_OFFSET_ctime + stx_mtime = STATX_OFFSET_mtime + CODE: +#if HAVE_STATX + struct statx_timestamp *ts = (struct statx_timestamp *)((char *)&stx + ix); + RETVAL = ts->tv_sec + ts->tv_nsec * 1e-9; +#else + XSRETURN_UNDEF; +#endif + OUTPUT: + RETVAL + +VAL64 +stx_atimesec () + PROTOTYPE: + ALIAS: + stx_atimesec = STATX_OFFSET_atime + stx_btimesec = STATX_OFFSET_btime + stx_ctimesec = STATX_OFFSET_ctime + stx_mtimesec = STATX_OFFSET_mtime + CODE: +#if HAVE_STATX + struct statx_timestamp *ts = (struct statx_timestamp *)((char *)&stx + ix); + RETVAL = ts->tv_sec; +#else + XSRETURN_UNDEF; +#endif + OUTPUT: + RETVAL + +U32 +stx_atimensec () + PROTOTYPE: + ALIAS: + stx_atimensec = STATX_OFFSET_atime + stx_btimensec = STATX_OFFSET_btime + stx_ctimensec = STATX_OFFSET_ctime + stx_mtimensec = STATX_OFFSET_mtime + CODE: +#if HAVE_STATX + struct statx_timestamp *ts = (struct statx_timestamp *)((char *)&stx + ix); + RETVAL = ts->tv_nsec; +#else + RETVAL = 0; +#endif + OUTPUT: + RETVAL + +void +accept4 (aio_rfd rfh, SV *sockaddr, int salen, int flags) + PPCODE: +{ + SV *retval; +#if HAVE_ACCEPT4 + socklen_t salen_ = salen ? salen + 1 : 0; + + if (salen) + { + sv_upgrade (sockaddr, SVt_PV); + sv_grow (sockaddr, salen_); + } + + int res = accept4 (rfh, salen ? (struct sockaddr *)SvPVX (sockaddr) : 0, salen ? &salen_ : 0, flags); + + retval = newmortalFH (res, O_RDWR); + + if (res >= 0 && salen > 0) + { + if (salen_ > salen + 1) + salen_ = salen + 1; + + SvPOK_only (sockaddr); + SvCUR_set (sockaddr, salen_); + } +#else + errno = ENOSYS; + retval = &PL_sv_undef; +#endif + XPUSHs (retval); +} + +ssize_t splice (aio_rfd rfh, SV *off_in, aio_wfd wfh, SV *off_out, size_t length, unsigned int flags) CODE: { @@ -2274,7 +2590,7 @@ OUTPUT: RETVAL -int +ssize_t tee (aio_rfd rfh, aio_wfd wfh, size_t length, unsigned int flags) CODE: #if HAVE_LINUX_SPLICE @@ -2327,6 +2643,54 @@ } void +pidfd_open (int pid, unsigned int flags = 0) + PPCODE: +{ + /*GENDEF0_SYSCALL(pidfd_open,434)*/ + int fd = syscall (SYS_pidfd_open, pid, flags); + XPUSHs (newmortalFH (fd, O_RDWR)); +} + +int +pidfd_send_signal (SV *pidfh, int sig, SV *siginfo = &PL_sv_undef, unsigned int flags = 0) + PPCODE: +{ + int res; + siginfo_t si = { 0 }; + + if (SvOK (siginfo)) + { + HV *hv; + SV **svp; + + if (!SvROK (siginfo) || SvTYPE (SvRV (siginfo)) != SVt_PVHV) + croak ("siginfo argument must be a hashref code, pid, uid and value_int or value_ptr members, caught"); + + hv = (HV *)SvRV (siginfo); + + if ((svp = hv_fetchs (hv, "code" , 0))) si.si_code = SvIV (*svp); + if ((svp = hv_fetchs (hv, "pid" , 0))) si.si_pid = SvIV (*svp); + if ((svp = hv_fetchs (hv, "uid" , 0))) si.si_uid = SvIV (*svp); + if ((svp = hv_fetchs (hv, "value_int", 0))) si.si_value.sival_int = SvIV (*svp); + if ((svp = hv_fetchs (hv, "value_ptr", 0))) si.si_value.sival_ptr = (void *)SvIV (*svp); + } + + /*GENDEF0_SYSCALL(pidfd_send_signal,424)*/ + res = syscall (SYS_pidfd_send_signal, s_fileno_croak (pidfh, 0), sig, SvOK (siginfo) ? &si : 0, flags); + + XPUSHs (sv_2mortal (newSViv (res))); +} + +void +pidfd_getfd (SV *pidfh, int targetfd, unsigned int flags = 0) + PPCODE: +{ + /*GENDEF0_SYSCALL(pidfd_getfd,438)*/ + int fd = syscall (SYS_pidfd_getfd, s_fileno_croak (pidfh, 0), targetfd, flags); + XPUSHs (newmortalFH (fd, O_RDWR)); +} + +void eventfd (unsigned int initval = 0, int flags = 0) PPCODE: { @@ -2399,6 +2763,20 @@ #endif } +void +memfd_create (SV8 *pathname, int flags = 0) + PPCODE: +{ + int fd; +#if HAVE_MEMFD_CREATE + fd = memfd_create (SvPVbyte_nolen (pathname), flags); +#else + fd = (errno = ENOSYS, -1); +#endif + + XPUSHs (newmortalFH (fd, O_RDWR)); +} + UV get_fdlimit () CODE: @@ -2441,7 +2819,7 @@ if (errno == EPERM) { - /* setlimit failed with EPERM - maybe we can't raise the hardlimit, or maybe */ + /* setrlimit 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; @@ -2450,7 +2828,7 @@ rl.rlim_max |= bit; rl.rlim_cur = rl.rlim_max; - /* nevr decrease the hard limit */ + /* never decrease the hard limit */ if (rl.rlim_max < orig_rlim_max) break;