diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-11-22 08:46:51 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-11-22 08:46:51 +0000 |
commit | 6a65f2b1e479f268489b51a004b6c153c634c68a (patch) | |
tree | 5e7bae4d2418fd88b152380075eb6a1f21f2401b /thread.c | |
parent | b009de13bf4bb7c96964c404fb56b3503db777fd (diff) |
io + socket: make pipes and sockets nonblocking by default
All normal Ruby IO methods (IO#read, IO#gets, IO#write, ...) are
all capable of appearing to be "blocking" when presented with a
file description with the O_NONBLOCK flag set; so there is
little risk of incompatibility within Ruby-using programs.
The biggest compatibility risk is when spawning external
programs. As a result, stdin, stdout, and stderr are now always
made blocking before exec-family calls.
This change will make an event-oriented MJIT usable if it is
waiting on pipes on POSIX_like platforms.
It is ALSO necessary to take advantage of (proposed lightweight
concurrency (aka "auto-Fiber") or any similar proposal for
network concurrency: https://bugs.ruby-lang.org/issues/13618
Named-pipe (FIFO) are NOT yet non-blocking by default since
they are rarely-used and may introduce compatibility problems
and extra syscall overhead for a common path.
Please revert this commit if there are problems and if I am afk
since I am afk a lot, lately.
[ruby-core:89950] [Bug #14968]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65922 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'thread.c')
-rw-r--r-- | thread.c | 31 |
1 files changed, 20 insertions, 11 deletions
@@ -4068,17 +4068,19 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) int result = 0, lerrno; rb_hrtime_t *to, rel, end = 0; int drained; - rb_thread_t *th = GET_THREAD(); nfds_t nfds; rb_unblock_function_t *ubf; + struct waiting_fd wfd; - RUBY_VM_CHECK_INTS_BLOCKING(th->ec); + wfd.th = GET_THREAD(); + wfd.fd = fd; + RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec); timeout_prepare(&to, &rel, &end, timeout); fds[0].fd = fd; fds[0].events = (short)events; do { fds[0].revents = 0; - fds[1].fd = rb_sigwait_fd_get(th); + fds[1].fd = rb_sigwait_fd_get(wfd.th); if (fds[1].fd >= 0) { fds[1].events = POLLIN; @@ -4092,27 +4094,29 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) } lerrno = 0; - BLOCKING_REGION(th, { + list_add(&wfd.th->vm->waiting_fds, &wfd.wfd_node); + BLOCKING_REGION(wfd.th, { const rb_hrtime_t *sto; struct timespec ts; - sto = sigwait_timeout(th, fds[1].fd, to, &drained); - if (!RUBY_VM_INTERRUPTED(th->ec)) { + sto = sigwait_timeout(wfd.th, fds[1].fd, to, &drained); + if (!RUBY_VM_INTERRUPTED(wfd.th->ec)) { result = ppoll(fds, nfds, rb_hrtime2timespec(&ts, sto), NULL); if (result < 0) lerrno = errno; } - }, ubf, th, TRUE); + }, ubf, wfd.th, TRUE); + list_del(&wfd.wfd_node); if (fds[1].fd >= 0) { if (result > 0 && fds[1].revents) { result--; fds[1].revents = 0; } - (void)check_signals_nogvl(th, fds[1].fd); - rb_sigwait_fd_put(th, fds[1].fd); - rb_sigwait_fd_migrate(th->vm); + (void)check_signals_nogvl(wfd.th, fds[1].fd); + rb_sigwait_fd_put(wfd.th, fds[1].fd); + rb_sigwait_fd_migrate(wfd.th->vm); } - RUBY_VM_CHECK_INTS_BLOCKING(th->ec); + RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec); } while (wait_retryable(&result, lerrno, to, end)); if (result < 0) { @@ -4152,6 +4156,7 @@ struct select_args { rb_fdset_t *read; rb_fdset_t *write; rb_fdset_t *except; + struct waiting_fd wfd; struct timeval *tv; }; @@ -4182,6 +4187,7 @@ select_single_cleanup(VALUE ptr) { struct select_args *args = (struct select_args *)ptr; + list_del(&args->wfd.wfd_node); if (args->read) rb_fd_term(args->read); if (args->write) rb_fd_term(args->write); if (args->except) rb_fd_term(args->except); @@ -4202,7 +4208,10 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *tv) args.write = (events & RB_WAITFD_OUT) ? init_set_fd(fd, &wfds) : NULL; args.except = (events & RB_WAITFD_PRI) ? init_set_fd(fd, &efds) : NULL; args.tv = tv; + args.wfd.fd = fd; + args.wfd.th = GET_THREAD(); + list_add(&args.wfd.th->vm->waiting_fds, &args.wfd.wfd_node); r = (int)rb_ensure(select_single, ptr, select_single_cleanup, ptr); if (r == -1) errno = args.as.error; |