thread.c (rb_wait_for_single_fd): do not miss IO#close notifications
RUBY_VM_CHECK_INTS_BLOCKING may switch threads and cause `fd' to be closed. So we must ensure we register the waiting_fd before checking for interrupts. This only affects the ppoll/poll-using implementation of rb_wait_for_single_fd, as the select-based implementation already register waiting_fd before checking for interrupts. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65940 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a6a7d988b4
commit
dab99d4e27
93
thread.c
93
thread.c
@ -4071,53 +4071,60 @@ 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;
|
||||||
struct waiting_fd wfd;
|
struct waiting_fd wfd;
|
||||||
|
int state;
|
||||||
|
|
||||||
wfd.th = GET_THREAD();
|
wfd.th = GET_THREAD();
|
||||||
wfd.fd = fd;
|
wfd.fd = fd;
|
||||||
RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec);
|
list_add(&wfd.th->vm->waiting_fds, &wfd.wfd_node);
|
||||||
timeout_prepare(&to, &rel, &end, timeout);
|
EC_PUSH_TAG(wfd.th->ec);
|
||||||
fds[0].fd = fd;
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||||
fds[0].events = (short)events;
|
|
||||||
do {
|
|
||||||
fds[0].revents = 0;
|
|
||||||
fds[1].fd = rb_sigwait_fd_get(wfd.th);
|
|
||||||
|
|
||||||
if (fds[1].fd >= 0) {
|
|
||||||
fds[1].events = POLLIN;
|
|
||||||
fds[1].revents = 0;
|
|
||||||
nfds = 2;
|
|
||||||
ubf = ubf_sigwait;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nfds = 1;
|
|
||||||
ubf = ubf_select;
|
|
||||||
}
|
|
||||||
|
|
||||||
lerrno = 0;
|
|
||||||
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(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, 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(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(wfd.th->ec);
|
RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec);
|
||||||
} while (wait_retryable(&result, lerrno, to, end));
|
timeout_prepare(&to, &rel, &end, timeout);
|
||||||
|
fds[0].fd = fd;
|
||||||
|
fds[0].events = (short)events;
|
||||||
|
fds[0].revents = 0;
|
||||||
|
do {
|
||||||
|
fds[1].fd = rb_sigwait_fd_get(wfd.th);
|
||||||
|
|
||||||
|
if (fds[1].fd >= 0) {
|
||||||
|
fds[1].events = POLLIN;
|
||||||
|
fds[1].revents = 0;
|
||||||
|
nfds = 2;
|
||||||
|
ubf = ubf_sigwait;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nfds = 1;
|
||||||
|
ubf = ubf_select;
|
||||||
|
}
|
||||||
|
|
||||||
|
lerrno = 0;
|
||||||
|
BLOCKING_REGION(wfd.th, {
|
||||||
|
const rb_hrtime_t *sto;
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
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), 0);
|
||||||
|
if (result < 0) lerrno = errno;
|
||||||
|
}
|
||||||
|
}, ubf, wfd.th, TRUE);
|
||||||
|
|
||||||
|
if (fds[1].fd >= 0) {
|
||||||
|
if (result > 0 && fds[1].revents) {
|
||||||
|
result--;
|
||||||
|
}
|
||||||
|
(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(wfd.th->ec);
|
||||||
|
} while (wait_retryable(&result, lerrno, to, end));
|
||||||
|
}
|
||||||
|
EC_POP_TAG();
|
||||||
|
list_del(&wfd.wfd_node);
|
||||||
|
if (state) {
|
||||||
|
EC_JUMP_TAG(wfd.th->ec, state);
|
||||||
|
}
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
errno = lerrno;
|
errno = lerrno;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user