summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-03-30 19:11:17 +1300
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-03-30 23:16:59 +1300
commita9c5c2d614f30a616970245fef3e7ffc151e2ecf (patch)
tree7c33e368b99b479cc0cfe01db4d27d453fa96976
parent611e711085c7e3984555a79626d025c8b876eced (diff)
Check errno before invoking scheduler in `rb_io_wait_readable/writable`.
See <https://bugs.ruby-lang.org/issues/17527> for more details.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4338
-rw-r--r--io.c66
1 files changed, 35 insertions, 31 deletions
diff --git a/io.c b/io.c
index 5151114..ee792f4 100644
--- a/io.c
+++ b/io.c
@@ -1305,71 +1305,75 @@ rb_io_from_fd(int fd)
int
rb_io_wait_readable(int f)
{
+ io_fd_check_closed(f);
+
VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- return RTEST(
- rb_fiber_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f))
- );
- }
- io_fd_check_closed(f);
switch (errno) {
case EINTR:
#if defined(ERESTART)
case ERESTART:
#endif
- rb_thread_check_ints();
- return TRUE;
+ rb_thread_check_ints();
+ return TRUE;
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
- rb_thread_wait_fd(f);
- return TRUE;
+ if (scheduler != Qnil) {
+ return RTEST(
+ rb_fiber_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f))
+ );
+ } else {
+ rb_thread_wait_fd(f);
+ }
+ return TRUE;
default:
- return FALSE;
+ return FALSE;
}
}
int
rb_io_wait_writable(int f)
{
+ io_fd_check_closed(f);
+
VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- return RTEST(
- rb_fiber_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f))
- );
- }
- io_fd_check_closed(f);
switch (errno) {
case EINTR:
#if defined(ERESTART)
case ERESTART:
#endif
- /*
- * 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.
- */
- rb_thread_check_ints();
- return TRUE;
+ /*
+ * 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.
+ */
+ rb_thread_check_ints();
+ return TRUE;
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
- rb_thread_fd_writable(f);
- return TRUE;
+ if (scheduler != Qnil) {
+ return RTEST(
+ rb_fiber_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f))
+ );
+ } else {
+ rb_thread_fd_writable(f);
+ }
+ return TRUE;
default:
- return FALSE;
+ return FALSE;
}
}