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

ruby-changes:54236

From: normal <ko1@a...>
Date: Thu, 20 Dec 2018 09:07:24 +0900 (JST)
Subject: [ruby-changes:54236] normal:r66457 (trunk): thread_pthread.c (ubf_timer_disarm): ignore EINVAL iff timer is dead

normal	2018-12-20 09:07:19 +0900 (Thu, 20 Dec 2018)

  New Revision: 66457

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

  Log:
    thread_pthread.c (ubf_timer_disarm): ignore EINVAL iff timer is dead
    
    The following race may happen if ubf_timer_destroy calls
    timer_delete before ubf_timer_disarm gets called from
    a different thread.  Consider the following timelines:
    
      ubf_timer_destroy                    | ubf_timer_disarm
      -------------------------------------+-----------------------------
                                           | CAS(ARM => DISARM)
      CAS(DISARM => DEAD)                  |
      timer_delete                         |
                                           | timer_settime(disarm)
    
    Another option may be to add an intermediate "RTIMER_DISARMING"
    state to the transition, but I figure the EINVAL check is
    simpler and less intrusive code-wise.
    
    cf. http://ci.rvm.jp/results/trunk-iseq_binary@silicon-docker/1545794

  Modified files:
    trunk/thread_pthread.c
Index: thread_pthread.c
===================================================================
--- thread_pthread.c	(revision 66456)
+++ thread_pthread.c	(revision 66457)
@@ -1769,8 +1769,18 @@ ubf_timer_disarm(void) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L1769
       case RTIMER_DISARM: return; /* likely */
       case RTIMER_ARMING: return; /* ubf_timer_arm will disarm itself */
       case RTIMER_ARMED:
-        if (timer_settime(timer_posix.timerid, 0, &zero, 0))
-            rb_bug_errno("timer_settime (disarm)", errno);
+        if (timer_settime(timer_posix.timerid, 0, &zero, 0)) {
+            int err = errno;
+
+            if (err == EINVAL) {
+                prev = ATOMIC_CAS(timer_posix.state, RTIMER_DISARM, RTIMER_DISARM);
+
+                /* main thread may have killed the timer */
+                if (prev == RTIMER_DEAD) return;
+
+                rb_bug_errno("timer_settime (disarm)", err);
+            }
+        }
         return;
       case RTIMER_DEAD: return; /* stay dead */
       default:

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

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