summaryrefslogtreecommitdiff
path: root/thread_pthread.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-18 18:25:54 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-18 18:25:54 +0000
commita57acb731a8bdcc17f66b6a50ce3eba55058c721 (patch)
tree821541903919c76f3ce64aa588beee1946c3829a /thread_pthread.c
parent75f36bdc1e48e9c4c870b920113f82ee962691fd (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.c31
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");