diff --git a/ext/-test-/wait_for_single_fd/depend b/ext/-test-/wait_for_single_fd/depend deleted file mode 100644 index 2f943245f7..0000000000 --- a/ext/-test-/wait_for_single_fd/depend +++ /dev/null @@ -1,165 +0,0 @@ -# AUTOGENERATED DEPENDENCIES START -wait_for_single_fd.o: $(RUBY_EXTCONF_H) -wait_for_single_fd.o: $(arch_hdrdir)/ruby/config.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/anyargs.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/char.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/double.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/int.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/long.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/short.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/assume.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/alloc_size.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/artificial.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/cold.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/const.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/constexpr.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/deprecated.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/error.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/flag_enum.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/forceinline.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/format.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/noalias.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/nodiscard.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/noexcept.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/noinline.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/nonnull.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/noreturn.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/pure.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/restrict.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/warning.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/attr/weakref.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/cast.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/apple.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/clang.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/intel.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/compiler_since.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/config.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/constant_p.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rarray.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rbasic.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rbignum.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rclass.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rdata.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rfile.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rhash.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/robject.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rregexp.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rstring.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rstruct.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/core/rtypeddata.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/ctype.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/dllexport.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/dosish.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/error.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/eval.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/event.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/fl_type.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/gc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/glob.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/globals.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/attribute.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/builtin.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/c_attribute.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/extension.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/feature.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/has/warning.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/array.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/bignum.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/class.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/compar.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/complex.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/cont.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/dir.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/enum.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/enumerator.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/error.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/eval.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/file.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/gc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/hash.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/io.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/load.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/marshal.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/numeric.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/object.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/parse.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/proc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/process.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/random.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/range.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/rational.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/re.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/ruby.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/select.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/select/largesize.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/signal.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/sprintf.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/string.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/struct.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/thread.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/time.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/variable.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/intern/vm.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/interpreter.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/iterator.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/memory.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/method.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/module.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/newobj.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/rgengc.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/scan_args.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/special_consts.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/static_assert.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/stdalign.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/stdbool.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/symbol.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/value.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/value_type.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/variable.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/warning_push.h -wait_for_single_fd.o: $(hdrdir)/ruby/internal/xmalloc.h -wait_for_single_fd.o: $(hdrdir)/ruby/assert.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/assume.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/attributes.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/bool.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/inttypes.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/limits.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/long_long.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/stdalign.h -wait_for_single_fd.o: $(hdrdir)/ruby/backward/2/stdarg.h -wait_for_single_fd.o: $(hdrdir)/ruby/defines.h -wait_for_single_fd.o: $(hdrdir)/ruby/encoding.h -wait_for_single_fd.o: $(hdrdir)/ruby/intern.h -wait_for_single_fd.o: $(hdrdir)/ruby/io.h -wait_for_single_fd.o: $(hdrdir)/ruby/missing.h -wait_for_single_fd.o: $(hdrdir)/ruby/onigmo.h -wait_for_single_fd.o: $(hdrdir)/ruby/oniguruma.h -wait_for_single_fd.o: $(hdrdir)/ruby/ruby.h -wait_for_single_fd.o: $(hdrdir)/ruby/st.h -wait_for_single_fd.o: $(hdrdir)/ruby/subst.h -wait_for_single_fd.o: wait_for_single_fd.c -# AUTOGENERATED DEPENDENCIES END diff --git a/ext/-test-/wait_for_single_fd/extconf.rb b/ext/-test-/wait_for_single_fd/extconf.rb deleted file mode 100644 index c27100fb42..0000000000 --- a/ext/-test-/wait_for_single_fd/extconf.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: false -case RUBY_PLATFORM when /mingw/ then - # skip -else - headers = %w(sys/types.h sys/time.h sys/event.h).select { |h| have_header(h) } - have_func('kqueue', headers) -end -create_makefile("-test-/wait_for_single_fd") diff --git a/ext/-test-/wait_for_single_fd/wait_for_single_fd.c b/ext/-test-/wait_for_single_fd/wait_for_single_fd.c deleted file mode 100644 index b8a33979bc..0000000000 --- a/ext/-test-/wait_for_single_fd/wait_for_single_fd.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "ruby/ruby.h" -#include "ruby/io.h" - -static VALUE -wait_for_single_fd(VALUE ign, VALUE fd, VALUE events, VALUE timeout) -{ - struct timeval tv; - struct timeval *tvp = NULL; - int rc; - - if (!NIL_P(timeout)) { - tv = rb_time_timeval(timeout); - tvp = &tv; - } - - rc = rb_wait_for_single_fd(NUM2INT(fd), NUM2INT(events), tvp); - if (rc == -1) - rb_sys_fail("rb_wait_for_single_fd"); - return INT2NUM(rc); -} - -#ifdef HAVE_KQUEUE -/* ensure rb_wait_for_single_fd works on kqueue descriptors */ -#include -#include -#include -static VALUE -kqueue_test_wait(VALUE klass) -{ - int kqfd = -1; - int p[2] = { -1, -1 }; - struct timeval tv = { 0, 0 }; - const struct timespec ts = { 1, 0 }; - struct kevent kev; - const char *msg; - VALUE ret = Qfalse; - int e = 0; - int n; - - msg = "pipe"; - if (rb_cloexec_pipe(p) < 0) goto err; - - msg = "kqueue"; - kqfd = kqueue(); - if (kqfd < 0) goto err; - - n = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN, &tv); - if (n != 0) { - msg = "spurious wakeup"; - errno = 0; - goto err; - } - - msg = "write"; - if (write(p[1], "", 1) < 0) goto err; - - EV_SET(&kev, p[0], EVFILT_READ, EV_ADD, 0, 0, 0); - - msg = "kevent"; - n = kevent(kqfd, &kev, 1, &kev, 1, &ts); - if (n < 0) goto err; - msg = NULL; - if (n == 1) { - n = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN, &tv); - ret = INT2NUM(n); - } - else { - rb_warn("kevent did not return readiness"); - } -err: - if (msg) e = errno; - if (p[0] >= 0) close(p[0]); - if (p[1] >= 0) close(p[1]); - if (kqfd >= 0) close(kqfd); - if (msg) { - if (e) rb_syserr_fail(e, msg); - rb_raise(rb_eRuntimeError, "%s", msg); - } - return ret; -} -#endif /* HAVE_KQUEUE */ - -void -Init_wait_for_single_fd(void) -{ - rb_define_const(rb_cObject, "RB_WAITFD_IN", INT2NUM(RB_WAITFD_IN)); - rb_define_const(rb_cObject, "RB_WAITFD_OUT", INT2NUM(RB_WAITFD_OUT)); - rb_define_const(rb_cObject, "RB_WAITFD_PRI", INT2NUM(RB_WAITFD_PRI)); - rb_define_singleton_method(rb_cIO, "wait_for_single_fd", - wait_for_single_fd, 3); -#ifdef HAVE_KQUEUE - rb_define_singleton_method(rb_cIO, "kqueue_test_wait", kqueue_test_wait, 0); -#endif -} diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index c38142bfcc..0511579d7b 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1639,12 +1639,12 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(fptr->fd); + rb_io_maybe_wait_writable(errno, fptr->self, Qnil); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(fptr->fd); + rb_io_maybe_wait_readable(errno, fptr->self, Qnil); continue; case SSL_ERROR_SYSCALL: #ifdef __APPLE__ @@ -1819,12 +1819,12 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(fptr->fd); + rb_io_maybe_wait_writable(errno, fptr->self, Qnil); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(fptr->fd); + rb_io_maybe_wait_readable(errno, fptr->self, Qnil); continue; case SSL_ERROR_SYSCALL: if (!ERR_peek_error()) { @@ -1935,12 +1935,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) case SSL_ERROR_WANT_WRITE: if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); - rb_io_wait_writable(fptr->fd); + rb_io_maybe_wait_writable(errno, fptr->self, Qnil); continue; case SSL_ERROR_WANT_READ: if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); - rb_io_wait_readable(fptr->fd); + rb_io_maybe_wait_readable(errno, fptr->self, Qnil); continue; case SSL_ERROR_SYSCALL: #ifdef __APPLE__ diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c index 546a971760..4ec3f3d0a8 100644 --- a/ext/socket/ancdata.c +++ b/ext/socket/ancdata.c @@ -1279,7 +1279,7 @@ bsock_sendmsg_internal(VALUE sock, VALUE data, VALUE vflags, if (ss == -1) { int e; - if (!nonblock && rb_io_wait_writable(fptr->fd)) { + if (!nonblock && rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) { rb_io_check_closed(fptr); goto retry; } @@ -1551,7 +1551,7 @@ bsock_recvmsg_internal(VALUE sock, if (ss == -1) { int e; - if (!nonblock && rb_io_wait_readable(fptr->fd)) { + if (!nonblock && rb_io_maybe_wait_readable(errno, fptr->self, Qnil)) { rb_io_check_closed(fptr); goto retry; } diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c index 6168698df1..05172100c8 100644 --- a/ext/socket/basicsocket.c +++ b/ext/socket/basicsocket.c @@ -537,12 +537,11 @@ bsock_remote_address(VALUE sock) * } */ VALUE -rsock_bsock_send(int argc, VALUE *argv, VALUE sock) +rsock_bsock_send(int argc, VALUE *argv, VALUE socket) { struct rsock_send_arg arg; VALUE flags, to; rb_io_t *fptr; - ssize_t n; rb_blocking_function_t *func; const char *funcname; @@ -550,28 +549,38 @@ rsock_bsock_send(int argc, VALUE *argv, VALUE sock) StringValue(arg.mesg); if (!NIL_P(to)) { - SockAddrStringValue(to); - to = rb_str_new4(to); - arg.to = (struct sockaddr *)RSTRING_PTR(to); - arg.tolen = RSTRING_SOCKLEN(to); - func = rsock_sendto_blocking; - funcname = "sendto(2)"; + SockAddrStringValue(to); + to = rb_str_new4(to); + arg.to = (struct sockaddr *)RSTRING_PTR(to); + arg.tolen = RSTRING_SOCKLEN(to); + func = rsock_sendto_blocking; + funcname = "sendto(2)"; } else { - func = rsock_send_blocking; - funcname = "send(2)"; + func = rsock_send_blocking; + funcname = "send(2)"; } - GetOpenFile(sock, fptr); + + RB_IO_POINTER(socket, fptr); + arg.fd = fptr->fd; arg.flags = NUM2INT(flags); - while (rsock_maybe_fd_writable(arg.fd), - (n = (ssize_t)BLOCKING_REGION_FD(func, &arg)) < 0) { - if (rb_io_maybe_wait_writable(errno, sock, Qnil)) { - continue; - } - rb_sys_fail(funcname); + + while (true) { +#ifdef RSOCK_WAIT_BEFORE_BLOCKING + rb_io_wait(socket, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil); +#endif + + ssize_t n = (ssize_t)BLOCKING_REGION_FD(func, &arg); + + if (n >= 0) return SSIZET2NUM(n); + + if (rb_io_maybe_wait_writable(errno, socket, Qnil)) { + continue; + } + + rb_sys_fail(funcname); } - return SSIZET2NUM(n); } /* diff --git a/ext/socket/init.c b/ext/socket/init.c index 8eb8c8e901..5859c33e29 100644 --- a/ext/socket/init.c +++ b/ext/socket/init.c @@ -198,7 +198,10 @@ rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from) while (true) { rb_io_check_closed(fptr); - rsock_maybe_wait_fd(arg.fd); + +#ifdef RSOCK_WAIT_BEFORE_BLOCKING + rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil); +#endif slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp, (VALUE)&arg); @@ -701,11 +704,13 @@ rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len) .len = len }; - int retry = 0; + int retry = 0, peer; retry: - rsock_maybe_wait_fd(accept_arg.fd); - int peer = (int)BLOCKING_REGION_FD(accept_blocking, &accept_arg); +#ifdef RSOCK_WAIT_BEFORE_BLOCKING + rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil); +#endif + peer = (int)BLOCKING_REGION_FD(accept_blocking, &accept_arg); if (peer < 0) { int error = errno; diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index a7755660e9..c0d40addca 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -432,30 +432,17 @@ NORETURN(void rsock_sys_fail_sockaddr(const char *, struct sockaddr *addr, sockl NORETURN(void rsock_sys_fail_raddrinfo(const char *, VALUE rai)); NORETURN(void rsock_sys_fail_raddrinfo_or_sockaddr(const char *, VALUE addr, VALUE rai)); -/* - * It is safe on Linux to attempt using a socket without waiting on it in - * all cases. For some syscalls (e.g. accept/accept4), blocking on the - * syscall instead of relying on select/poll allows the kernel to use - * "wake-one" behavior and avoid the thundering herd problem. - * This is likely safe on all other *nix-like systems, so this safe list - * can be expanded by interested parties. - */ -#if defined(__linux__) -static inline int rsock_maybe_fd_writable(int fd) { return 1; } -static inline void rsock_maybe_wait_fd(int fd) { } -# ifdef MSG_DONTWAIT -# define MSG_DONTWAIT_RELIABLE 1 -# endif -#else /* some systems (mswin/mingw) need these. ref: r36946 */ -# define rsock_maybe_fd_writable(fd) rb_thread_fd_writable((fd)) -# define rsock_maybe_wait_fd(fd) rb_thread_wait_fd((fd)) +#if defined(__MINGW32__) || defined(_WIN32) +#define RSOCK_WAIT_BEFORE_BLOCKING #endif /* * some OSes may support MSG_DONTWAIT inconsistently depending on socket * type, we only expect Linux to support it consistently for all socket types. */ -#ifndef MSG_DONTWAIT_RELIABLE +#if defined(MSG_DONTWAIT) && defined(__linux__) +# define MSG_DONTWAIT_RELIABLE 1 +#else # define MSG_DONTWAIT_RELIABLE 0 #endif diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c index 593f05522d..94ea19c224 100644 --- a/ext/socket/udpsocket.c +++ b/ext/socket/udpsocket.c @@ -153,23 +153,26 @@ udp_send_internal(VALUE v) { struct udp_send_arg *arg = (void *)v; rb_io_t *fptr; - int n; struct addrinfo *res; rb_io_check_closed(fptr = arg->fptr); for (res = arg->res->ai; res; res = res->ai_next) { retry: - arg->sarg.fd = fptr->fd; - arg->sarg.to = res->ai_addr; - arg->sarg.tolen = res->ai_addrlen; - rsock_maybe_fd_writable(arg->sarg.fd); - n = (int)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg->sarg); - if (n >= 0) { - return INT2FIX(n); - } - if (rb_io_wait_writable(fptr->fd)) { - goto retry; - } + arg->sarg.fd = fptr->fd; + arg->sarg.to = res->ai_addr; + arg->sarg.tolen = res->ai_addrlen; + +#ifdef RSOCK_WAIT_BEFORE_BLOCKING + rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil); +#endif + + ssize_t n = (ssize_t)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg->sarg); + + if (n >= 0) return RB_INT2NUM(n); + + if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) { + goto retry; + } } return Qfalse; } diff --git a/include/ruby/internal/intern/thread.h b/include/ruby/internal/intern/thread.h index a12a371058..dd591474ce 100644 --- a/include/ruby/internal/intern/thread.h +++ b/include/ruby/internal/intern/thread.h @@ -31,8 +31,8 @@ struct timeval; /* thread.c */ void rb_thread_schedule(void); -void rb_thread_wait_fd(int); -int rb_thread_fd_writable(int); +#define rb_thread_wait_fd(fd) rb_wait_for_single_fd((fd), RUBY_IO_READABLE, NULL) +#define rb_thread_fd_writable(fd) rb_wait_for_single_fd((fd), RUBY_IO_WRITABLE, NULL) void rb_thread_fd_close(int); int rb_thread_alone(void); void rb_thread_sleep(int); diff --git a/include/ruby/io.h b/include/ruby/io.h index bf916a5f8e..9a6b65cb2c 100644 --- a/include/ruby/io.h +++ b/include/ruby/io.h @@ -154,8 +154,13 @@ int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding ** void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p); ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size); +RBIMPL_ATTR_DEPRECATED(("use rb_io_maybe_wait_readable")) int rb_io_wait_readable(int fd); + +RBIMPL_ATTR_DEPRECATED(("use rb_io_maybe_wait_writable")) int rb_io_wait_writable(int fd); + +RBIMPL_ATTR_DEPRECATED(("use rb_io_wait")) int rb_wait_for_single_fd(int fd, int events, struct timeval *tv); VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout); diff --git a/io.c b/io.c index c5cd348f4d..7db0560e71 100644 --- a/io.c +++ b/io.c @@ -492,7 +492,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd) #if defined(_WIN32) #define WAIT_FD_IN_WIN32(fptr) \ - (rb_w32_io_cancelable_p((fptr)->fd) ? 0 : rb_thread_wait_fd((fptr)->fd)) + (rb_w32_io_cancelable_p((fptr)->fd) ? 0 : RB_NUM2INT(rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))) #else #define WAIT_FD_IN_WIN32(fptr) #endif @@ -998,7 +998,7 @@ void rb_io_read_check(rb_io_t *fptr) { if (!READ_DATA_PENDING(fptr)) { - rb_thread_wait_fd(fptr->fd); + rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil); } return; } @@ -1248,13 +1248,17 @@ static int io_fflush(rb_io_t *fptr) { rb_io_check_closed(fptr); + if (fptr->wbuf.len == 0) return 0; + while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) { - if (!rb_io_wait_writable(fptr->fd)) - return -1; + if (!rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) + return -1; + rb_io_check_closed(fptr); } + return 0; } @@ -1296,11 +1300,25 @@ rb_io_wait(VALUE io, VALUE events, VALUE timeout) } static VALUE -rb_io_from_fd(int fd) +io_from_fd(int fd) { return prep_io(fd, FMODE_PREP, rb_cIO, NULL); } +static +int io_wait_for_single_fd(int fd, int events, struct timeval *timeout) +{ + VALUE scheduler = rb_fiber_scheduler_current(); + + if (scheduler != Qnil) { + return RTEST( + rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout)) + ); + } + + return rb_thread_wait_for_single_fd(fd, events, timeout); +} + int rb_io_wait_readable(int f) { @@ -1322,11 +1340,11 @@ rb_io_wait_readable(int f) #endif if (scheduler != Qnil) { return RTEST( - rb_fiber_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f)) + rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f)) ); } else { - rb_thread_wait_fd(f); + io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL); } return TRUE; @@ -1365,11 +1383,11 @@ rb_io_wait_writable(int f) #endif if (scheduler != Qnil) { return RTEST( - rb_fiber_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f)) + rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f)) ); } else { - rb_thread_fd_writable(f); + io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL); } return TRUE; @@ -1381,20 +1399,19 @@ rb_io_wait_writable(int f) int rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) { - VALUE scheduler = rb_fiber_scheduler_current(); - - if (scheduler != Qnil) { - return RTEST( - rb_fiber_scheduler_io_wait(scheduler, rb_io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout)) - ); - } - - return rb_thread_wait_for_single_fd(fd, events, timeout); + return io_wait_for_single_fd(fd, events, timeout); } VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout) { switch (error) { + // In old Linux, several special files under /proc and /sys don't handle + // select properly. Thus we need avoid to call if don't use O_NONBLOCK. + // Otherwise, we face nasty hang up. Sigh. + // e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 + // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 + // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING(). + // Then rb_thread_check_ints() is enough. case EINTR: #if defined(ERESTART) case ERESTART: @@ -1561,9 +1578,6 @@ io_binwrite_string(VALUE arg) return len; } - if (fptr->stdio_file != stderr && !rb_thread_fd_writable(fptr->fd)) - rb_io_check_closed(fptr); - return rb_write_internal(p->fptr->fd, p->ptr, p->length); } #endif @@ -1623,7 +1637,7 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) } if (r == -2L) return -1L; - if (rb_io_wait_writable(fptr->fd)) { + if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) { rb_io_check_closed(fptr); if (offset < len) goto retry; @@ -1861,7 +1875,7 @@ io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr) errno = EAGAIN; } - if (rb_io_wait_writable(fptr->fd)) { + if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) { rb_io_check_closed(fptr); goto retry; } @@ -2250,7 +2264,7 @@ rb_io_rewind(VALUE io) static int fptr_wait_readable(rb_io_t *fptr) { - int ret = rb_io_wait_readable(fptr->fd); + int ret = rb_io_maybe_wait_readable(errno, fptr->self, Qnil); if (ret) rb_io_check_closed(fptr); @@ -4689,7 +4703,7 @@ finish_writeconv(rb_io_t *fptr, int noalloc) if (0 <= r) { ds += r; } - if (rb_io_wait_writable(fptr->fd)) { + if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) { if (fptr->fd < 0) return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream)); goto retry; @@ -5332,7 +5346,7 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io) rb_io_check_byte_readable(fptr); if (READ_DATA_BUFFERED(fptr)) { - rb_raise(rb_eIOError, "sysread for buffered IO"); + rb_raise(rb_eIOError, "sysread for buffered IO"); } /* @@ -5342,7 +5356,7 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io) * the IO after we return from rb_thread_wait_fd() but before * we call read() */ - rb_thread_wait_fd(fptr->fd); + rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil); rb_io_check_closed(fptr); @@ -11104,7 +11118,7 @@ rb_thread_fiber_scheduler_wait_for_single_fd(void * _args) { struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args; - args->result = rb_fiber_scheduler_io_wait(args->scheduler, rb_io_from_fd(args->fd), INT2NUM(args->events), Qnil); + args->result = rb_fiber_scheduler_io_wait(args->scheduler, io_from_fd(args->fd), INT2NUM(args->events), Qnil); return NULL; } @@ -11170,12 +11184,12 @@ maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp) int ret; do { - if (has_gvl) { - ret = rb_wait_for_single_fd(stp->src_fd, RB_WAITFD_IN, NULL); - } - else { - ret = nogvl_wait_for_single_fd(stp->th, stp->src_fd, RB_WAITFD_IN); - } + if (has_gvl) { + ret = RB_NUM2INT(rb_io_wait(stp->src, RB_INT2NUM(RUBY_IO_READABLE), Qnil)); + } + else { + ret = nogvl_wait_for_single_fd(stp->th, stp->src_fd, RB_WAITFD_IN); + } } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp)); if (ret < 0) { diff --git a/ruby.c b/ruby.c index 0247c581b7..baa2f251c2 100644 --- a/ruby.c +++ b/ruby.c @@ -2305,7 +2305,7 @@ open_load_file(VALUE fname_v, int *xflag) We need to wait if FIFO is empty. It's FIFO's semantics. rb_thread_wait_fd() release GVL. So, it's safe. */ - rb_thread_wait_fd(fd); + rb_io_wait(f, RB_INT2NUM(RUBY_IO_READABLE), Qnil); } } return f; diff --git a/thread.c b/thread.c index 1511977d4d..ed771166e6 100644 --- a/thread.c +++ b/thread.c @@ -4296,39 +4296,6 @@ do_select(VALUE p) return (VALUE)result; } -static void -rb_thread_wait_fd_rw(int fd, int read) -{ - int result = 0; - int events = read ? RB_WAITFD_IN : RB_WAITFD_OUT; - - thread_debug("rb_thread_wait_fd_rw(%d, %s)\n", fd, read ? "read" : "write"); - - if (fd < 0) { - rb_raise(rb_eIOError, "closed stream"); - } - - result = rb_wait_for_single_fd(fd, events, NULL); - if (result < 0) { - rb_sys_fail(0); - } - - thread_debug("rb_thread_wait_fd_rw(%d, %s): done\n", fd, read ? "read" : "write"); -} - -void -rb_thread_wait_fd(int fd) -{ - rb_thread_wait_fd_rw(fd, 1); -} - -int -rb_thread_fd_writable(int fd) -{ - rb_thread_wait_fd_rw(fd, 0); - return TRUE; -} - static rb_fdset_t * init_set_fd(int fd, rb_fdset_t *fds) {