diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-12-18 18:25:54 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-12-18 18:25:54 +0000 |
commit | a57acb731a8bdcc17f66b6a50ce3eba55058c721 (patch) | |
tree | 821541903919c76f3ce64aa588beee1946c3829a /thread_pthread.c | |
parent | 75f36bdc1e48e9c4c870b920113f82ee962691fd (diff) |
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
Diffstat (limited to 'thread_pthread.c')
-rw-r--r-- | thread_pthread.c | 31 |
1 files changed, 27 insertions, 4 deletions
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"); |