The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

// readv/writev
#include <sys/uio.h>

// errno/EINTR
#include <errno.h>

// IOV_MAX
#include <limits.h>

#ifndef IOV_MAX
#  ifdef UIO_MAXIOV
#    define IOV_MAX UIO_MAXIOV
#  endif
#endif

#ifndef IOV_MAX
#  error "Unable to determine IOV_MAX from system headers"
#endif



MODULE = IO::Vectored		PACKAGE = IO::Vectored

PROTOTYPES: ENABLE


unsigned long
_backend(fileno, is_write, ...)
        int fileno
        int is_write
    CODE:
        ssize_t rv;
        int iovcnt;

        if (items < 3) croak("need more arguments to %s", is_write ? "syswritev" : "sysreadv");

        iovcnt = items - 2;
        if (iovcnt > IOV_MAX) croak("too many arguments to %s", is_write ? "syswritev" : "sysreadv");

        {
          struct iovec v[iovcnt]; // Needs C99 compiler
          SV *item;
          int i;
          size_t len;

          for(i=0; i<iovcnt; i++) {
            item = ST(2 + i);

            if (!is_write && SvREADONLY(item)) croak("Can't modify constant item in sysreadv"); 

            SvUPGRADE(item, SVt_PV);
            if (!SvPOK(item) && !SvIOK(item) && !SvNOK(item))
              croak("non-string object passed to %s", is_write ? "syswritev" : "sysreadv");
            SvPV_nolen(item);

            v[i].iov_len = len = SvCUR(item);
            if (is_write) {
              v[i].iov_base = SvPV(item, len);
            } else {
              v[i].iov_base = SvPV_force(item, len);
            }
          }

          again:

          if (is_write) {
            rv = writev(fileno, &v[0], iovcnt);
          } else {
            rv = readv(fileno, &v[0], iovcnt);
          }

          if (rv < 0 && errno == EINTR) goto again;
        }

        if (rv < 0) XSRETURN_UNDEF;

        RETVAL = (unsigned long) rv;
    OUTPUT:
        RETVAL


int
_get_iov_max()
    CODE:
        RETVAL = IOV_MAX;
    OUTPUT:
        RETVAL