mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	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
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66457 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
			
			
This commit is contained in:
		
							parent
							
								
									cb3393add5
								
							
						
					
					
						commit
						0b38221d4e
					
				
					 1 changed files with 12 additions and 2 deletions
				
			
		| 
						 | 
					@ -1769,8 +1769,18 @@ ubf_timer_disarm(void)
 | 
				
			||||||
      case RTIMER_DISARM: return; /* likely */
 | 
					      case RTIMER_DISARM: return; /* likely */
 | 
				
			||||||
      case RTIMER_ARMING: return; /* ubf_timer_arm will disarm itself */
 | 
					      case RTIMER_ARMING: return; /* ubf_timer_arm will disarm itself */
 | 
				
			||||||
      case RTIMER_ARMED:
 | 
					      case RTIMER_ARMED:
 | 
				
			||||||
        if (timer_settime(timer_posix.timerid, 0, &zero, 0))
 | 
					        if (timer_settime(timer_posix.timerid, 0, &zero, 0)) {
 | 
				
			||||||
            rb_bug_errno("timer_settime (disarm)", errno);
 | 
					            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;
 | 
					        return;
 | 
				
			||||||
      case RTIMER_DEAD: return; /* stay dead */
 | 
					      case RTIMER_DEAD: return; /* stay dead */
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue