thread.c: check interrupts explicitly in select/ppoll blocking regions

The logic around blocking_region_begin is confusing to me,
but the goal of this patch is to ensure rb_sigwait_fd_get
and rb_sigwait_fd_put are matched.

In other words, we don't want a thread to hold sigwait_fd
forever if an exception is raised while calling select()
or ppoll().

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64550 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2018-08-27 05:32:18 +00:00
Родитель bab586e787
Коммит 49a55f28ab
1 изменённых файлов: 15 добавлений и 8 удалений

Просмотреть файл

@ -3854,7 +3854,7 @@ static VALUE
do_select(VALUE p) do_select(VALUE p)
{ {
struct select_set *set = (struct select_set *)p; struct select_set *set = (struct select_set *)p;
int MAYBE_UNUSED(result); int result = 0;
int lerrno; int lerrno;
rb_hrtime_t *to, rel, end; rb_hrtime_t *to, rel, end;
@ -3876,10 +3876,13 @@ do_select(VALUE p)
struct timeval tv; struct timeval tv;
sto = sigwait_timeout(set->th, set->sigwait_fd, to, &drained); sto = sigwait_timeout(set->th, set->sigwait_fd, to, &drained);
result = native_fd_select(set->max, set->rset, set->wset, set->eset, if (!RUBY_VM_INTERRUPTED(set->th->ec)) {
rb_hrtime2timeval(&tv, sto), set->th); result = native_fd_select(set->max, set->rset, set->wset,
if (result < 0) lerrno = errno; set->eset,
}, set->sigwait_fd >= 0 ? ubf_sigwait : ubf_select, set->th, FALSE); rb_hrtime2timeval(&tv, sto), set->th);
if (result < 0) lerrno = errno;
}
}, set->sigwait_fd >= 0 ? ubf_sigwait : ubf_select, set->th, TRUE);
if (set->sigwait_fd >= 0) { if (set->sigwait_fd >= 0) {
if (result > 0 && rb_fd_isset(set->sigwait_fd, set->rset)) if (result > 0 && rb_fd_isset(set->sigwait_fd, set->rset))
@ -3949,6 +3952,7 @@ rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t *
struct select_set set; struct select_set set;
set.th = GET_THREAD(); set.th = GET_THREAD();
RUBY_VM_CHECK_INTS_BLOCKING(set.th->ec);
set.max = max; set.max = max;
set.sigwait_fd = rb_sigwait_fd_get(set.th); set.sigwait_fd = rb_sigwait_fd_get(set.th);
set.rset = read; set.rset = read;
@ -4018,6 +4022,7 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
nfds_t nfds; nfds_t nfds;
rb_unblock_function_t *ubf; rb_unblock_function_t *ubf;
RUBY_VM_CHECK_INTS_BLOCKING(th->ec);
timeout_prepare(&to, &rel, &end, timeout); timeout_prepare(&to, &rel, &end, timeout);
fds[0].fd = fd; fds[0].fd = fd;
fds[0].events = (short)events; fds[0].events = (short)events;
@ -4042,9 +4047,11 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
struct timespec ts; struct timespec ts;
sto = sigwait_timeout(th, fds[1].fd, to, &drained); sto = sigwait_timeout(th, fds[1].fd, to, &drained);
result = ppoll(fds, nfds, rb_hrtime2timespec(&ts, sto), NULL); if (!RUBY_VM_INTERRUPTED(th->ec)) {
if (result < 0) lerrno = errno; result = ppoll(fds, nfds, rb_hrtime2timespec(&ts, sto), NULL);
}, ubf, th, FALSE); if (result < 0) lerrno = errno;
}
}, ubf, th, TRUE);
if (fds[1].fd >= 0) { if (fds[1].fd >= 0) {
if (result > 0 && fds[1].revents) { if (result > 0 && fds[1].revents) {