Backport #6127 ยป ruby-io-c.patch
/Users/dlampa/carrier-build-root/local_build/carrier-ruby-1.9.3p194-2/src/ruby-build/ruby-source/io.c 2012-10-10 09:02:34.000000000 -0500 | ||
---|---|---|
if (max_file_descriptor < fd) max_file_descriptor = fd;
|
||
}
|
||
void
|
||
rb_maygvl_fd_fix_cloexec(int fd)
|
||
{
|
||
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
|
||
#ifdef F_GETFD
|
||
int flags, flags2, ret;
|
||
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
|
||
if (flags == -1) {
|
||
rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
|
||
}
|
||
if (fd <= 2)
|
||
flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
|
||
else
|
||
flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
|
||
if (flags != flags2) {
|
||
ret = fcntl(fd, F_SETFD, flags2);
|
||
if (ret == -1) {
|
||
rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
int
|
||
rb_cloexec_fcntl_dupfd(int fd, int minfd)
|
||
{
|
||
int ret;
|
||
#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
|
||
static int try_dupfd_cloexec = 1;
|
||
if (try_dupfd_cloexec) {
|
||
ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
|
||
if (ret != -1) {
|
||
if (ret <= 2)
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
return ret;
|
||
}
|
||
/* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
|
||
if (errno == EINVAL) {
|
||
ret = fcntl(fd, F_DUPFD, minfd);
|
||
if (ret != -1) {
|
||
try_dupfd_cloexec = 0;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
ret = fcntl(fd, F_DUPFD, minfd);
|
||
}
|
||
#else
|
||
ret = fcntl(fd, F_DUPFD, minfd);
|
||
#endif
|
||
if (ret == -1) return -1;
|
||
rb_maygvl_fd_fix_cloexec(ret);
|
||
return ret;
|
||
}
|
||
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
|
||
#define ARGF argf_of(argf)
|
||
... | ... | |
return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
|
||
}
|
||
struct io_cntl_arg {
|
||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||
typedef unsigned long ioctl_req_t;
|
||
#define NUM2IOCTLREQ(num) NUM2ULONG(num)
|
||
#else
|
||
typedef int ioctl_req_t;
|
||
#define NUM2IOCTLREQ(num) NUM2INT(num)
|
||
#endif
|
||
struct ioctl_arg {
|
||
int fd;
|
||
int cmd;
|
||
ioctl_req_t cmd;
|
||
long narg;
|
||
int io_p;
|
||
};
|
||
static VALUE nogvl_io_cntl(void *ptr)
|
||
static VALUE nogvl_ioctl(void *ptr)
|
||
{
|
||
struct io_cntl_arg *arg = ptr;
|
||
struct ioctl_arg *arg = ptr;
|
||
if (arg->io_p)
|
||
return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
|
||
else
|
||
return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
|
||
return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
|
||
}
|
||
static int
|
||
io_cntl(int fd, int cmd, long narg, int io_p)
|
||
do_ioctl(int fd, ioctl_req_t cmd, long narg)
|
||
{
|
||
int retval;
|
||
struct io_cntl_arg arg;
|
||
#ifndef HAVE_FCNTL
|
||
if (!io_p) {
|
||
rb_notimplement();
|
||
}
|
||
#endif
|
||
struct ioctl_arg arg;
|
||
arg.fd = fd;
|
||
arg.cmd = cmd;
|
||
arg.narg = narg;
|
||
arg.io_p = io_p;
|
||
retval = (int)rb_thread_io_blocking_region(nogvl_io_cntl, &arg, fd);
|
||
#if defined(F_DUPFD)
|
||
if (!io_p && retval != -1 && cmd == F_DUPFD) {
|
||
rb_update_max_fd(retval);
|
||
}
|
||
#endif
|
||
retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
|
||
return retval;
|
||
}
|
||
static VALUE
|
||
rb_io_ctl(VALUE io, VALUE req, VALUE arg, int io_p)
|
||
static long
|
||
ioctl_narg_len(ioctl_req_t cmd)
|
||
{
|
||
int cmd = NUM2INT(req);
|
||
rb_io_t *fptr;
|
||
long len = 0;
|
||
long narg = 0;
|
||
int retval;
|
||
long len;
|
||
rb_secure(2);
|
||
#ifdef IOCPARM_MASK
|
||
#ifndef IOCPARM_LEN
|
||
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||
#endif
|
||
#endif
|
||
#ifdef IOCPARM_LEN
|
||
len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
|
||
#elif defined(_IOC_SIZE)
|
||
len = _IOC_SIZE(cmd);
|
||
#else
|
||
len = 256; /* otherwise guess at what's safe */
|
||
#endif
|
||
return len;
|
||
}
|
||
#ifdef HAVE_FCNTL
|
||
#ifdef __linux__
|
||
typedef long fcntl_arg_t;
|
||
#else
|
||
/* posix */
|
||
typedef int fcntl_arg_t;
|
||
#endif
|
||
static long
|
||
fcntl_narg_len(int cmd)
|
||
{
|
||
long len;
|
||
switch (cmd) {
|
||
#ifdef F_DUPFD
|
||
case F_DUPFD:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_DUP2FD /* bsd specific */
|
||
case F_DUP2FD:
|
||
len = sizeof(int);
|
||
break;
|
||
#endif
|
||
#ifdef F_DUPFD_CLOEXEC /* linux specific */
|
||
case F_DUPFD_CLOEXEC:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETFD
|
||
case F_GETFD:
|
||
len = 1;
|
||
break;
|
||
#endif
|
||
#ifdef F_SETFD
|
||
case F_SETFD:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETFL
|
||
case F_GETFL:
|
||
len = 1;
|
||
break;
|
||
#endif
|
||
#ifdef F_SETFL
|
||
case F_SETFL:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETOWN
|
||
case F_GETOWN:
|
||
len = 1;
|
||
break;
|
||
#endif
|
||
#ifdef F_SETOWN
|
||
case F_SETOWN:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETOWN_EX /* linux specific */
|
||
case F_GETOWN_EX:
|
||
len = sizeof(struct f_owner_ex);
|
||
break;
|
||
#endif
|
||
#ifdef F_SETOWN_EX /* linux specific */
|
||
case F_SETOWN_EX:
|
||
len = sizeof(struct f_owner_ex);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETLK
|
||
case F_GETLK:
|
||
len = sizeof(struct flock);
|
||
break;
|
||
#endif
|
||
#ifdef F_SETLK
|
||
case F_SETLK:
|
||
len = sizeof(struct flock);
|
||
break;
|
||
#endif
|
||
#ifdef F_SETLKW
|
||
case F_SETLKW:
|
||
len = sizeof(struct flock);
|
||
break;
|
||
#endif
|
||
#ifdef F_READAHEAD /* bsd specific */
|
||
case F_READAHEAD:
|
||
len = sizeof(int);
|
||
break;
|
||
#endif
|
||
#ifdef F_RDAHEAD /* Darwin specific */
|
||
case F_RDAHEAD:
|
||
len = sizeof(int);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETSIG /* linux specific */
|
||
case F_GETSIG:
|
||
len = 1;
|
||
break;
|
||
#endif
|
||
#ifdef F_SETSIG /* linux specific */
|
||
case F_SETSIG:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_GETLEASE /* linux specific */
|
||
case F_GETLEASE:
|
||
len = 1;
|
||
break;
|
||
#endif
|
||
#ifdef F_SETLEASE /* linux specific */
|
||
case F_SETLEASE:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
#ifdef F_NOTIFY /* linux specific */
|
||
case F_NOTIFY:
|
||
len = sizeof(fcntl_arg_t);
|
||
break;
|
||
#endif
|
||
default:
|
||
len = 256;
|
||
break;
|
||
}
|
||
return len;
|
||
}
|
||
#else /* HAVE_FCNTL */
|
||
static long
|
||
fcntl_narg_len(int cmd)
|
||
{
|
||
return 0;
|
||
}
|
||
#endif /* HAVE_FCNTL */
|
||
static long
|
||
setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p)
|
||
{
|
||
long narg = 0;
|
||
VALUE arg = *argp;
|
||
if (NIL_P(arg) || arg == Qfalse) {
|
||
narg = 0;
|
||
... | ... | |
narg = NUM2LONG(arg);
|
||
}
|
||
else {
|
||
arg = tmp;
|
||
#ifdef IOCPARM_MASK
|
||
#ifndef IOCPARM_LEN
|
||
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
||
#endif
|
||
#endif
|
||
#ifdef IOCPARM_LEN
|
||
len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
|
||
#else
|
||
len = 256; /* otherwise guess at what's safe */
|
||
#endif
|
||
long len;
|
||
*argp = arg = tmp;
|
||
if (io_p)
|
||
len = ioctl_narg_len(cmd);
|
||
else
|
||
len = fcntl_narg_len((int)cmd);
|
||
rb_str_modify(arg);
|
||
if (len <= RSTRING_LEN(arg)) {
|
||
len = RSTRING_LEN(arg);
|
||
}
|
||
if (RSTRING_LEN(arg) < len) {
|
||
/* expand for data + sentinel. */
|
||
if (RSTRING_LEN(arg) < len+1) {
|
||
rb_str_resize(arg, len+1);
|
||
}
|
||
RSTRING_PTR(arg)[len] = 17; /* a little sanity check here */
|
||
/* a little sanity check here */
|
||
RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17;
|
||
narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg);
|
||
}
|
||
}
|
||
GetOpenFile(io, fptr);
|
||
retval = io_cntl(fptr->fd, cmd, narg, io_p);
|
||
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
if (TYPE(arg) == T_STRING && RSTRING_PTR(arg)[len] != 17) {
|
||
rb_raise(rb_eArgError, "return value overflowed string");
|
||
return narg;
|
||
}
|
||
if (!io_p && cmd == F_SETFL) {
|
||
if (narg & O_NONBLOCK) {
|
||
fptr->mode |= FMODE_WSPLIT_INITIALIZED;
|
||
fptr->mode &= ~FMODE_WSPLIT;
|
||
}
|
||
else {
|
||
fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
|
||
}
|
||
static VALUE
|
||
rb_ioctl(VALUE io, VALUE req, VALUE arg)
|
||
{
|
||
ioctl_req_t cmd = NUM2IOCTLREQ(req);
|
||
rb_io_t *fptr;
|
||
long narg;
|
||
int retval;
|
||
|
||
rb_secure(2);
|
||
narg = setup_narg(cmd, &arg, 1);
|
||
GetOpenFile(io, fptr);
|
||
retval = do_ioctl(fptr->fd, cmd, narg);
|
||
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
if (RB_TYPE_P(arg, T_STRING)) {
|
||
if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
|
||
rb_raise(rb_eArgError, "return value overflowed string");
|
||
RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
|
||
}
|
||
return INT2NUM(retval);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* ios.ioctl(integer_cmd, arg) -> integer
|
||
... | ... | |
VALUE req, arg;
|
||
rb_scan_args(argc, argv, "11", &req, &arg);
|
||
return rb_io_ctl(io, req, arg, 1);
|
||
return rb_ioctl(io, req, arg);
|
||
}
|
||
#ifdef HAVE_FCNTL
|
||
struct fcntl_arg {
|
||
int fd;
|
||
int cmd;
|
||
long narg;
|
||
};
|
||
static VALUE nogvl_fcntl(void *ptr)
|
||
{
|
||
struct fcntl_arg *arg = ptr;
|
||
#if defined(F_DUPFD)
|
||
if (arg->cmd == F_DUPFD)
|
||
return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
|
||
#endif
|
||
return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
|
||
}
|
||
static int
|
||
do_fcntl(int fd, int cmd, long narg)
|
||
{
|
||
int retval;
|
||
struct fcntl_arg arg;
|
||
arg.fd = fd;
|
||
arg.cmd = cmd;
|
||
arg.narg = narg;
|
||
retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
|
||
#if defined(F_DUPFD)
|
||
if (retval != -1 && cmd == F_DUPFD) {
|
||
rb_update_max_fd(retval);
|
||
}
|
||
#endif
|
||
return retval;
|
||
}
|
||
static VALUE
|
||
rb_fcntl(VALUE io, VALUE req, VALUE arg)
|
||
{
|
||
int cmd = NUM2INT(req);
|
||
rb_io_t *fptr;
|
||
long narg;
|
||
int retval;
|
||
rb_secure(2);
|
||
narg = setup_narg(cmd, &arg, 0);
|
||
GetOpenFile(io, fptr);
|
||
retval = do_fcntl(fptr->fd, cmd, narg);
|
||
if (retval < 0) rb_sys_fail_path(fptr->pathv);
|
||
if (RB_TYPE_P(arg, T_STRING)) {
|
||
if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
|
||
rb_raise(rb_eArgError, "return value overflowed string");
|
||
RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
|
||
}
|
||
if (cmd == F_SETFL) {
|
||
if (narg & O_NONBLOCK) {
|
||
fptr->mode |= FMODE_WSPLIT_INITIALIZED;
|
||
fptr->mode &= ~FMODE_WSPLIT;
|
||
}
|
||
else {
|
||
fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
|
||
}
|
||
}
|
||
return INT2NUM(retval);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* ios.fcntl(integer_cmd, arg) -> integer
|
||
... | ... | |
VALUE req, arg;
|
||
rb_scan_args(argc, argv, "11", &req, &arg);
|
||
return rb_io_ctl(io, req, arg, 0);
|
||
return rb_fcntl(io, req, arg);
|
||
}
|
||
#else
|
||
#define rb_io_fcntl rb_f_notimplement
|