File 0017-select_with_poll-do-not-raise-exception-on-bad-fd.patch of Package ruby2.5
From ae999facdd69d6e2768f69bef6d2e564efd9ce2a Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Wed, 4 Mar 2020 23:34:09 +0100
Subject: [PATCH 17/19] select_with_poll: do not raise exception on bad fd.
poll() returns an error for each bad descriptor rather than one global
error. FOrward the information to user.
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
---
include/ruby/intern.h | 8 ++++----
include/ruby/io.h | 2 +-
internal.h | 2 +-
io.c | 26 ++++++++++++++------------
thread.c | 28 +++++++++++++++++-----------
thread_pthread.c | 4 ++--
thread_win32.c | 3 ++-
7 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index ac1b0345afa9..c81ceeee20cc 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -313,7 +313,7 @@ void rb_fd_copy(rb_fdset_t *, const fd_set *, int);
void rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src);
struct timeval;
-int rb_fd_select(int, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, struct timeval *);
+int rb_fd_select(int, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, struct timeval *, _Bool);
#define rb_fd_ptr(f) ((f)->fdset)
#define rb_fd_max(f) ((f)->maxfd)
@@ -335,7 +335,7 @@ void rb_fd_set(int, rb_fdset_t *);
void rb_w32_fd_copy(rb_fdset_t *, const fd_set *, int);
#define rb_fd_dup(d, s) rb_w32_fd_dup((d), (s))
void rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src);
-#define rb_fd_select(n, rfds, wfds, efds, errfds, timeout) rb_w32_select((n), (rfds) ? ((rb_fdset_t*)(rfds))->fdset : NULL, (wfds) ? ((rb_fdset_t*)(wfds))->fdset : NULL, (efds) ? ((rb_fdset_t*)(efds))->fdset: NULL, (errfds) ? ((rb_fdset_t*)(errfds))->fdset: NULL, (timeout))
+#define rb_fd_select(n, rfds, wfds, efds, errfds, timeout, select_iface) rb_w32_select((n), (rfds) ? ((rb_fdset_t*)(rfds))->fdset : NULL, (wfds) ? ((rb_fdset_t*)(wfds))->fdset : NULL, (efds) ? ((rb_fdset_t*)(efds))->fdset: NULL, (errfds) ? ((rb_fdset_t*)(errfds))->fdset: NULL, (timeout))
#define rb_fd_resize(n, f) ((void)(f))
#define rb_fd_ptr(f) ((f)->fdset)
@@ -356,7 +356,7 @@ typedef fd_set rb_fdset_t;
#define rb_fd_init_copy(d, s) (*(d) = *(s))
#define rb_fd_term(f) ((void)(f))
#define rb_fd_max(f) FD_SETSIZE
-#define rb_fd_select(n, rfds, wfds, efds, errfds, timeout) select((n), (rfds), (wfds), (efds), (timeout))
+#define rb_fd_select(n, rfds, wfds, efds, errfds, timeout, select_iface) select((n), (rfds), (wfds), (efds), (timeout))
#endif
@@ -435,7 +435,7 @@ VALUE rb_thread_wakeup_alive(VALUE);
VALUE rb_thread_run(VALUE);
VALUE rb_thread_kill(VALUE);
VALUE rb_thread_create(VALUE (*)(ANYARGS), void*);
-int rb_thread_fd_select(int, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, struct timeval *);
+int rb_thread_fd_select(int, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, rb_fdset_t *, struct timeval *, _Bool);
void rb_thread_wait_for(struct timeval);
VALUE rb_thread_current(void);
VALUE rb_thread_main(void);
diff --git a/include/ruby/io.h b/include/ruby/io.h
index 11d2120e0ac8..00708058e379 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -43,7 +43,7 @@ extern "C" {
# define RB_WAITFD_IN POLLIN
# define RB_WAITFD_PRI POLLPRI
# define RB_WAITFD_OUT POLLOUT
-# define RB_WAITFD_ERR (POLLHUP|POLLERR)
+# define RB_WAITFD_ERR (POLLHUP|POLLERR|POLLNVAL)
#else
# define RB_WAITFD_IN 0x001
# define RB_WAITFD_PRI 0x002
diff --git a/internal.h b/internal.h
index 21bc37ba7ac4..19aeb97c1787 100644
--- a/internal.h
+++ b/internal.h
@@ -97,7 +97,7 @@ extern "C" {
#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN)
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT)
#define POLLEX_SET (POLLPRI)
-#define POLLERR_SET (POLLHUP | POLLERR)
+#define POLLERR_SET (POLLHUP | POLLERR | POLLNVAL)
#endif
#if GCC_VERSION_SINCE(4, 6, 0) || __has_extension(c_static_assert)
diff --git a/io.c b/io.c
index 033c11ef4869..4a3b6cce05b6 100644
--- a/io.c
+++ b/io.c
@@ -8906,7 +8906,7 @@ rb_f_backquote(VALUE obj, VALUE str)
#endif
static VALUE
-select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timeval *tp, rb_fdset_t *fds)
+select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timeval *tp, _Bool select_iface, rb_fdset_t *fds)
{
VALUE res, list;
rb_fdset_t *rp, *wp, *ep, *erp;
@@ -8969,7 +8969,7 @@ select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timev
ep = 0;
}
- if (!NIL_P(error)) {
+ if (!NIL_P(error) && !select_iface) {
Check_Type(error, T_ARRAY);
for (i=0; i<RARRAY_LEN(error); i++) {
VALUE io = rb_io_get_io(RARRAY_AREF(error, i));
@@ -8991,7 +8991,7 @@ select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timev
max++;
- n = rb_thread_fd_select(max, rp, wp, ep, erp, tp);
+ n = rb_thread_fd_select(max, rp, wp, ep, erp, tp, select_iface);
if (n < 0) {
rb_sys_fail(0);
}
@@ -9001,7 +9001,8 @@ select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timev
rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
- rb_ary_push(res, erp?rb_ary_new():rb_ary_new2(0));
+ if (!select_iface)
+ rb_ary_push(res, erp?rb_ary_new():rb_ary_new2(0));
if (rp) {
list = RARRAY_AREF(res, 0);
@@ -9073,6 +9074,7 @@ select_internal(VALUE read, VALUE write, VALUE except, VALUE error, struct timev
struct select_args {
VALUE read, write, except, error;
struct timeval *timeout;
+ bool select_iface;
rb_fdset_t fdsets[5];
};
@@ -9081,7 +9083,7 @@ select_call(VALUE arg)
{
struct select_args *p = (struct select_args *)arg;
- return select_internal(p->read, p->write, p->except, p->error, p->timeout, p->fdsets);
+ return select_internal(p->read, p->write, p->except, p->error, p->timeout, p->select_iface, p->fdsets);
}
static VALUE
@@ -9289,8 +9291,9 @@ rb_io_advise(int argc, VALUE *argv, VALUE io)
*
* On systems that support poll(2) system call IO.select_with_poll is provided
* which takes and returns extra array of descriptors. Descriptors in this
- * extra array and all other arrays are checked for error conditions -
- * typically the other side closing the pipe or socket.
+ * extra array are checked for error conditions - typically the other side
+ * closing the pipe or socket. Descriptors returned in fourth array instead of
+ * raising Errno::EBADF.
*
* IO.select peeks the buffer of IO objects for testing readability.
* If the IO buffer is not empty, IO.select immediately notifies
@@ -9429,21 +9432,20 @@ rb_f_select_with_poll(int argc, VALUE *argv, VALUE obj)
struct select_args args;
rb_scan_args(argc, argv, "14", &args.read, &args.write, &args.except, &args.error, &timeout);
+ args.select_iface = false;
return do_rb_f_select(&args, timeout);
}
#endif
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
- VALUE timeout, rv;
+ VALUE timeout;
struct select_args args;
rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
args.error = Qnil;
- rv = do_rb_f_select(&args, timeout);
- if (RB_TYPE_P(rv, T_ARRAY))
- rb_ary_pop(rv);
- return rv;
+ args.select_iface = true;
+ return do_rb_f_select(&args, timeout);
}
static VALUE
diff --git a/thread.c b/thread.c
index 76d60def5cf4..76e379a4acf3 100644
--- a/thread.c
+++ b/thread.c
@@ -3706,7 +3706,7 @@ pollfdset_extract(struct rb_pollfdset *pollfdset, rb_fdset_t *fds, int flags)
rb_fd_zero(fds);
for (i = 0; i < pollfdset->n_fds; i++)
- if (pollfdset->fds[i].revents & (flags | POLLERR_SET))
+ if (pollfdset->fds[i].revents & flags)
rb_fd_set(pollfdset->fds[i].fd, fds);
}
@@ -3723,11 +3723,12 @@ pollfdset_badfd(struct rb_pollfdset *pollfdset)
}
int
-rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds, struct timeval *timeout)
+rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds,
+ struct timeval *timeout, _Bool select_iface)
{
struct rb_pollfdset pollfdset;
int timeout_ms = timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1;
- bool badfd;
+ bool badfd = false;
int ret;
pollfdset_init(&pollfdset);
@@ -3736,14 +3737,16 @@ rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *excep
if (exceptfds) pollfdset_add(&pollfdset, exceptfds, POLLEX_SET);
if (errorfds) pollfdset_add(&pollfdset, errorfds, POLLERR_SET);
ret = poll(pollfdset.fds, pollfdset.n_fds, timeout_ms);
- badfd = pollfdset_badfd(&pollfdset);
+ if (select_iface)
+ badfd = pollfdset_badfd(&pollfdset);
if (badfd) {
if (readfds) rb_fd_zero(readfds);
if (writefds) rb_fd_zero(writefds);
if (exceptfds) rb_fd_zero(exceptfds);
if (errorfds) rb_fd_zero(errorfds);
} else {
- if (readfds) pollfdset_extract(&pollfdset, readfds, POLLIN_SET);
+ if (readfds) pollfdset_extract(&pollfdset, readfds, POLLIN_SET |
+ (select_iface ? POLLERR_SET : 0));
if (writefds) pollfdset_extract(&pollfdset, writefds, POLLOUT_SET);
if (exceptfds) pollfdset_extract(&pollfdset, exceptfds, POLLEX_SET);
if (errorfds) pollfdset_extract(&pollfdset, errorfds, POLLERR_SET);
@@ -3758,7 +3761,7 @@ rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *excep
}
#else /* USE_POLL */
int
-rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds, struct timeval *timeout)
+rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds, struct timeval *timeout, _Bool select_iface)
{
fd_set *r = NULL, *w = NULL, *e = NULL;
if (readfds) {
@@ -3911,7 +3914,7 @@ static const rb_data_type_t select_set_type = {
static int
do_select(int n, rb_fdset_t *const readfds, rb_fdset_t *const writefds,
- rb_fdset_t *const exceptfds, rb_fdset_t *const errorfds, struct timeval *timeout)
+ rb_fdset_t *const exceptfds, rb_fdset_t *const errorfds, struct timeval *timeout, bool select_iface)
{
int MAYBE_UNUSED(result);
int lerrno;
@@ -3951,7 +3954,7 @@ do_select(int n, rb_fdset_t *const readfds, rb_fdset_t *const writefds,
BLOCKING_REGION({
result = native_fd_select(n, readfds, writefds, exceptfds, errorfds,
- timeout, th);
+ timeout, select_iface, th);
if (result < 0) lerrno = errno;
}, ubf_select, th, FALSE);
@@ -4001,7 +4004,7 @@ rb_thread_fd_writable(int fd)
int
rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t * except,
- rb_fdset_t * error, struct timeval *timeout)
+ rb_fdset_t * error, struct timeval *timeout, _Bool select_iface)
{
if (!read && !write && !except && !error) {
if (!timeout) {
@@ -4021,7 +4024,10 @@ rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t *
if (except) {
rb_fd_resize(max - 1, except);
}
- return do_select(max, read, write, except, error, timeout);
+ if (error) {
+ rb_fd_resize(max - 1, error);
+ }
+ return do_select(max, read, write, except, error, timeout, select_iface);
}
#if USE_POLL
@@ -4162,7 +4168,7 @@ select_single(VALUE ptr)
int r;
r = rb_thread_fd_select(args->as.fd + 1,
- args->read, args->write, args->except, args->error, args->tv);
+ args->read, args->write, args->except, args->error, args->tv, true);
if (r == -1)
args->as.error = errno;
if (r > 0) {
diff --git a/thread_pthread.c b/thread_pthread.c
index b98e8bb73831..d2386aea86f1 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -1084,9 +1084,9 @@ native_thread_apply_priority(rb_thread_t *th)
#endif /* USE_NATIVE_THREAD_PRIORITY */
static int
-native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds, struct timeval *timeout, rb_thread_t *th)
+native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, rb_fdset_t *errorfds, struct timeval *timeout, _Bool select_iface, rb_thread_t *th)
{
- return rb_fd_select(n, readfds, writefds, exceptfds, errorfds, timeout);
+ return rb_fd_select(n, readfds, writefds, exceptfds, errorfds, timeout, select_iface);
}
static void
diff --git a/thread_win32.c b/thread_win32.c
index 5619fb462c41..caf82a6a01fe 100644
--- a/thread_win32.c
+++ b/thread_win32.c
@@ -629,7 +629,8 @@ native_thread_apply_priority(rb_thread_t *th)
int rb_w32_select_with_thread(int, fd_set *, fd_set *, fd_set *, struct timeval *, void *); /* @internal */
static int
-native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
+native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds,
+ struct timeval *timeout, _Bool select_iface, rb_thread_t *th)
{
fd_set *r = NULL, *w = NULL, *e = NULL;
if (readfds) {
--
2.26.2