[前][次][番号順一覧][スレッド一覧]

ruby-changes:53724

From: normal <ko1@a...>
Date: Sat, 24 Nov 2018 07:01:41 +0900 (JST)
Subject: [ruby-changes:53724] normal:r65940 (trunk): thread.c (rb_wait_for_single_fd): do not miss IO#close notifications

normal	2018-11-24 07:01:35 +0900 (Sat, 24 Nov 2018)

  New Revision: 65940

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65940

  Log:
    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.

  Modified files:
    trunk/thread.c
Index: thread.c
===================================================================
--- thread.c	(revision 65939)
+++ thread.c	(revision 65940)
@@ -4071,53 +4071,60 @@ rb_wait_for_single_fd(int fd, int events https://github.com/ruby/ruby/blob/trunk/thread.c#L4071
     nfds_t nfds;
     rb_unblock_function_t *ubf;
     struct waiting_fd wfd;
+    int state;
 
     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 {
+    list_add(&wfd.th->vm->waiting_fds, &wfd.wfd_node);
+    EC_PUSH_TAG(wfd.th->ec);
+    if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+        RUBY_VM_CHECK_INTS_BLOCKING(wfd.th->ec);
+        timeout_prepare(&to, &rel, &end, timeout);
+        fds[0].fd = fd;
+        fds[0].events = (short)events;
         fds[0].revents = 0;
-        fds[1].fd = rb_sigwait_fd_get(wfd.th);
+        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;
-        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;
+            if (fds[1].fd >= 0) {
+                fds[1].events = POLLIN;
+                fds[1].revents = 0;
+                nfds = 2;
+                ubf = ubf_sigwait;
+            }
+            else {
+                nfds = 1;
+                ubf = ubf_select;
             }
-        }, 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;
+            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);
             }
-            (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));
+            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) {
 	errno = lerrno;

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]