From a57acb731a8bdcc17f66b6a50ce3eba55058c721 Mon Sep 17 00:00:00 2001 From: normal Date: Tue, 18 Dec 2018 18:25:54 +0000 Subject: thread_pthread.c (ubf_timer_destroy): more careful state transition We must not call timer_destroy while another thread is calling timer_settime to arm the timer. cf. http://ci.rvm.jp/results/trunk-iseq_binary@silicon-docker/1541578 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66446 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- thread_pthread.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'thread_pthread.c') diff --git a/thread_pthread.c b/thread_pthread.c index 745c55544e..b087d461c7 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1787,11 +1787,34 @@ ubf_timer_destroy(void) { #if UBF_TIMER == UBF_TIMER_POSIX if (timer_posix.owner == getpid()) { - /* prevent signal handler from arming: */ - ATOMIC_SET(timer_posix.state, RTIMER_DEAD); + rb_atomic_t expect = RTIMER_DISARM; + size_t i, max = 10000000; - if (timer_settime(timer_posix.timerid, 0, &zero, 0)) - rb_bug_errno("timer_settime (destroy)", errno); + /* prevent signal handler from arming: */ + for (i = 0; i < max; i++) { + switch (ATOMIC_CAS(timer_posix.state, expect, RTIMER_DEAD)) { + case RTIMER_DISARM: + if (expect == RTIMER_DISARM) goto done; + expect = RTIMER_DISARM; + break; + case RTIMER_ARMING: + native_thread_yield(); /* let another thread finish arming */ + expect = RTIMER_ARMED; + break; + case RTIMER_ARMED: + if (expect == RTIMER_ARMED) { + if (timer_settime(timer_posix.timerid, 0, &zero, 0)) + rb_bug_errno("timer_settime (destroy)", errno); + goto done; + } + expect = RTIMER_ARMED; + break; + case RTIMER_DEAD: + rb_bug("RTIMER_DEAD unexpected"); + } + } + rb_bug("timed out waiting for timer to arm"); +done: if (timer_delete(timer_posix.timerid) < 0) rb_sys_fail("timer_delete"); -- cgit v1.2.3