diff options
Diffstat (limited to 'spec/ruby/optional/capi/ext/io_spec.c')
| -rw-r--r-- | spec/ruby/optional/capi/ext/io_spec.c | 319 |
1 files changed, 216 insertions, 103 deletions
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c index 40069bd54b..fe31cffb49 100644 --- a/spec/ruby/optional/capi/ext/io_spec.c +++ b/spec/ruby/optional/capi/ext/io_spec.c @@ -21,33 +21,27 @@ static int set_non_blocking(int fd) { int flags = 1; return ioctl(fd, FIOBIO, &flags); #else +#define SET_NON_BLOCKING_FAILS_ALWAYS 1 errno = ENOSYS; return -1; #endif } -#ifdef HAVE_GET_OPEN_FILE static int io_spec_get_fd(VALUE io) { - rb_io_t* fp; - GetOpenFile(io, fp); - return fp->fd; + return rb_io_descriptor(io); } VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) { return INT2NUM(io_spec_get_fd(io)); } -#endif -#ifdef HAVE_RB_IO_ADDSTR VALUE io_spec_rb_io_addstr(VALUE self, VALUE io, VALUE str) { return rb_io_addstr(io, str); } -#endif -#ifdef HAVE_RB_IO_PRINTF VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { @@ -56,12 +50,10 @@ VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) { return rb_io_printf((int)argc, argv, io); } -#endif -#ifdef HAVE_RB_IO_PRINT VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { @@ -70,12 +62,10 @@ VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) { return rb_io_print((int)argc, argv, io); } -#endif -#ifdef HAVE_RB_IO_PUTS VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) { long argc = RARRAY_LEN(ary); - VALUE *argv = alloca(sizeof(VALUE) * argc); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); int i; for (i = 0; i < argc; i++) { @@ -84,68 +74,61 @@ VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) { return rb_io_puts((int)argc, argv, io); } -#endif -#ifdef HAVE_RB_IO_WRITE VALUE io_spec_rb_io_write(VALUE self, VALUE io, VALUE str) { return rb_io_write(io, str); } -#endif -#ifdef HAVE_RB_IO_CHECK_IO VALUE io_spec_rb_io_check_io(VALUE self, VALUE io) { return rb_io_check_io(io); } -#endif -#ifdef HAVE_RB_IO_CHECK_READABLE VALUE io_spec_rb_io_check_readable(VALUE self, VALUE io) { rb_io_t* fp; GetOpenFile(io, fp); rb_io_check_readable(fp); return Qnil; } -#endif -#ifdef HAVE_RB_IO_CHECK_WRITABLE VALUE io_spec_rb_io_check_writable(VALUE self, VALUE io) { rb_io_t* fp; GetOpenFile(io, fp); rb_io_check_writable(fp); return Qnil; } -#endif -#ifdef HAVE_RB_IO_CHECK_CLOSED VALUE io_spec_rb_io_check_closed(VALUE self, VALUE io) { rb_io_t* fp; GetOpenFile(io, fp); rb_io_check_closed(fp); return Qnil; } -#endif -#ifdef HAVE_RB_IO_TAINT_CHECK VALUE io_spec_rb_io_taint_check(VALUE self, VALUE io) { /*rb_io_t* fp; GetOpenFile(io, fp);*/ rb_io_taint_check(io); return io; } -#endif -#ifdef HAVE_RB_IO_WAIT_READABLE #define RB_IO_WAIT_READABLE_BUF 13 +#ifdef SET_NON_BLOCKING_FAILS_ALWAYS +NORETURN(VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p)); +#endif + VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { int fd = io_spec_get_fd(io); +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS char buf[RB_IO_WAIT_READABLE_BUF]; int ret, saved_errno; +#endif if (set_non_blocking(fd) == -1) rb_sys_fail("set_non_blocking failed"); - if(RTEST(read_p)) { +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + if (RTEST(read_p)) { if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { return Qnil; } @@ -154,9 +137,9 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { errno = saved_errno; } - ret = rb_io_wait_readable(fd); + ret = rb_io_maybe_wait_readable(errno, io, Qnil); - if(RTEST(read_p)) { + if (RTEST(read_p)) { ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); if (r != RB_IO_WAIT_READABLE_BUF) { perror("read"); @@ -167,135 +150,265 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { } return ret ? Qtrue : Qfalse; -} +#else + UNREACHABLE_RETURN(Qnil); #endif +} -#ifdef HAVE_RB_IO_WAIT_WRITABLE VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) { - int ret = rb_io_wait_writable(io_spec_get_fd(io)); + int ret = rb_io_maybe_wait_writable(errno, io, Qnil); return ret ? Qtrue : Qfalse; } + +VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) { + int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout); + return INT2NUM(ret); +} + +#ifdef SET_NON_BLOCKING_FAILS_ALWAYS +NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p)); #endif -#ifdef HAVE_RB_THREAD_WAIT_FD +VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) { + int fd = io_spec_get_fd(io); +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + char buf[RB_IO_WAIT_READABLE_BUF]; + int ret, saved_errno; +#endif + + if (set_non_blocking(fd) == -1) + rb_sys_fail("set_non_blocking failed"); + +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + if (RTEST(read_p)) { + if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { + return Qnil; + } + saved_errno = errno; + rb_ivar_set(self, rb_intern("@write_data"), Qtrue); + errno = saved_errno; + } + + // main part + ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout); + + if (RTEST(read_p)) { + ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); + if (r != RB_IO_WAIT_READABLE_BUF) { + perror("read"); + return SSIZET2NUM(r); + } + rb_ivar_set(self, rb_intern("@read_data"), + rb_str_new(buf, RB_IO_WAIT_READABLE_BUF)); + } + + return INT2NUM(ret); +#else + UNREACHABLE_RETURN(Qnil); +#endif +} + +VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) { + return rb_io_maybe_wait(NUM2INT(error), io, events, timeout); +} + VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) { rb_thread_wait_fd(io_spec_get_fd(io)); return Qnil; } -#endif -#ifdef HAVE_RB_THREAD_FD_WRITABLE +VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE secs, VALUE usecs) { + VALUE timeout = Qnil; + if (!NIL_P(secs)) { + timeout = rb_float_new((double)FIX2INT(secs) + (0.000001 * FIX2INT(usecs))); + } + VALUE result = rb_io_wait(io, events, timeout); + if (result == Qfalse) return INT2FIX(0); + else return result; +} + VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) { rb_thread_fd_writable(io_spec_get_fd(io)); return Qnil; } -#endif -#ifdef HAVE_RB_IO_BINMODE +VALUE io_spec_rb_thread_fd_select_read(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, &fds, NULL, NULL, NULL); + rb_fd_term(&fds); + return INT2FIX(r); +} + +VALUE io_spec_rb_thread_fd_select_write(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, NULL); + rb_fd_term(&fds); + return INT2FIX(r); +} + +VALUE io_spec_rb_thread_fd_select_timeout(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 20; + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, &timeout); + rb_fd_term(&fds); + return INT2FIX(r); +} + VALUE io_spec_rb_io_binmode(VALUE self, VALUE io) { return rb_io_binmode(io); } -#endif -#ifdef HAVE_RB_FD_FIX_CLOEXEC VALUE io_spec_rb_fd_fix_cloexec(VALUE self, VALUE io) { rb_fd_fix_cloexec(io_spec_get_fd(io)); return Qnil; } -#endif -#ifdef HAVE_RB_CLOEXEC_OPEN VALUE io_spec_rb_cloexec_open(VALUE self, VALUE path, VALUE flags, VALUE mode) { const char *pathname = StringValuePtr(path); int fd = rb_cloexec_open(pathname, FIX2INT(flags), FIX2INT(mode)); return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(fd)); } -#endif -#ifdef HAVE_RB_IO_CLOSE +VALUE io_spec_rb_cloexec_dup(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + int new_fd = rb_cloexec_dup(fd); + return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd)); +} + +VALUE io_spec_rb_cloexec_fcntl_dupfd(VALUE self, VALUE io, VALUE minfd) { + int fd = io_spec_get_fd(io); + int new_fd = rb_cloexec_fcntl_dupfd(fd, FIX2INT(minfd)); + return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd)); +} + VALUE io_spec_rb_io_close(VALUE self, VALUE io) { return rb_io_close(io); } + +VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) { + rb_io_t* fp; +#ifdef F_GETFL + int flags; #endif + GetOpenFile(io, fp); + rb_io_set_nonblock(fp); +#ifdef F_GETFL + flags = fcntl(io_spec_get_fd(io), F_GETFL, 0); + return flags & O_NONBLOCK ? Qtrue : Qfalse; +#else + return Qfalse; +#endif +} + +/* + * this is needed to ensure rb_io_wait_*able functions behave + * predictably because errno may be set to unexpected values + * otherwise. + */ +static VALUE io_spec_errno_set(VALUE self, VALUE val) { + int e = NUM2INT(val); + errno = e; + return val; +} + +VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) { + int mode; + mode = rb_io_mode(io); + if (mode & FMODE_SYNC) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) { + return INT2FIX(rb_io_mode(io)); +} + +static VALUE io_spec_rb_io_path(VALUE self, VALUE io) { + return rb_io_path(io); +} + +static VALUE io_spec_rb_io_closed_p(VALUE self, VALUE io) { + return rb_io_closed_p(io); +} + +static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout, VALUE internal_encoding, VALUE external_encoding, VALUE ecflags, VALUE ecopts) { + struct rb_io_encoding io_encoding; + + io_encoding.enc = rb_to_encoding(internal_encoding); + io_encoding.enc2 = rb_to_encoding(external_encoding); + io_encoding.ecflags = FIX2INT(ecflags); + io_encoding.ecopts = ecopts; + + return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, &io_encoding); +} + +static VALUE io_spec_rb_io_open_descriptor_without_encoding(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout) { + return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, NULL); +} void Init_io_spec(void) { VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject); - -#ifdef HAVE_GET_OPEN_FILE rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1); -#endif - -#ifdef HAVE_RB_IO_ADDSTR rb_define_method(cls, "rb_io_addstr", io_spec_rb_io_addstr, 2); -#endif - -#ifdef HAVE_RB_IO_PRINTF rb_define_method(cls, "rb_io_printf", io_spec_rb_io_printf, 2); -#endif - -#ifdef HAVE_RB_IO_PRINT rb_define_method(cls, "rb_io_print", io_spec_rb_io_print, 2); -#endif - -#ifdef HAVE_RB_IO_PUTS rb_define_method(cls, "rb_io_puts", io_spec_rb_io_puts, 2); -#endif - -#ifdef HAVE_RB_IO_WRITE rb_define_method(cls, "rb_io_write", io_spec_rb_io_write, 2); -#endif - -#ifdef HAVE_RB_IO_CLOSE rb_define_method(cls, "rb_io_close", io_spec_rb_io_close, 1); -#endif - -#ifdef HAVE_RB_IO_CHECK_IO rb_define_method(cls, "rb_io_check_io", io_spec_rb_io_check_io, 1); -#endif - -#ifdef HAVE_RB_IO_CHECK_READABLE rb_define_method(cls, "rb_io_check_readable", io_spec_rb_io_check_readable, 1); -#endif - -#ifdef HAVE_RB_IO_CHECK_WRITABLE rb_define_method(cls, "rb_io_check_writable", io_spec_rb_io_check_writable, 1); -#endif - -#ifdef HAVE_RB_IO_CHECK_CLOSED rb_define_method(cls, "rb_io_check_closed", io_spec_rb_io_check_closed, 1); -#endif - -#ifdef HAVE_RB_IO_TAINT_CHECK + rb_define_method(cls, "rb_io_set_nonblock", io_spec_rb_io_set_nonblock, 1); rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1); -#endif - -#ifdef HAVE_RB_IO_WAIT_READABLE rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2); -#endif - -#ifdef HAVE_RB_IO_WAIT_WRITABLE rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1); -#endif - -#ifdef HAVE_RB_THREAD_WAIT_FD + rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3); + rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4); + rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4); rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1); -#endif - -#ifdef HAVE_RB_THREAD_FD_WRITABLE rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1); -#endif - -#ifdef HAVE_RB_IO_BINMODE + rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1); + rb_define_method(cls, "rb_thread_fd_select_write", io_spec_rb_thread_fd_select_write, 1); + rb_define_method(cls, "rb_thread_fd_select_timeout", io_spec_rb_thread_fd_select_timeout, 1); + rb_define_method(cls, "rb_wait_for_single_fd", io_spec_rb_wait_for_single_fd, 4); rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1); -#endif - -#ifdef HAVE_RB_FD_FIX_CLOEXEC rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1); -#endif - -#ifdef HAVE_RB_CLOEXEC_OPEN rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3); -#endif + rb_define_method(cls, "rb_cloexec_dup", io_spec_rb_cloexec_dup, 1); + rb_define_method(cls, "rb_cloexec_fcntl_dupfd", io_spec_rb_cloexec_fcntl_dupfd, 2); + rb_define_method(cls, "errno=", io_spec_errno_set, 1); + rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1); + rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1); + rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1); + rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1); + rb_define_method(cls, "rb_io_open_descriptor", io_spec_rb_io_open_descriptor, 9); + rb_define_method(cls, "rb_io_open_descriptor_without_encoding", io_spec_rb_io_open_descriptor_without_encoding, 5); + rb_define_const(cls, "FMODE_READABLE", INT2FIX(FMODE_READABLE)); + rb_define_const(cls, "FMODE_WRITABLE", INT2FIX(FMODE_WRITABLE)); + rb_define_const(cls, "FMODE_BINMODE", INT2FIX(FMODE_BINMODE)); + rb_define_const(cls, "FMODE_TEXTMODE", INT2FIX(FMODE_TEXTMODE)); + rb_define_const(cls, "ECONV_UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR)); } #ifdef __cplusplus |
