Feature #15002 ยป 0001-thread.c-sleep_-reduce-the-effect-of-spurious-interr.patch
| signal.c | ||
|---|---|---|
| } | ||
| #endif | ||
| static void | ||
| static int | ||
| signal_exec(VALUE cmd, int safe, int sig) | ||
| { | ||
|     rb_execution_context_t *ec = GET_EC(); | ||
| ... | ... | |
|      * 3. rb_signal_exec runs on queued signal | ||
|      */ | ||
|     if (IMMEDIATE_P(cmd)) | ||
| 	return; | ||
| 	return FALSE; | ||
|     ec->interrupt_mask |= TRAP_INTERRUPT_MASK; | ||
|     EC_PUSH_TAG(ec); | ||
| ... | ... | |
| 	/* XXX: should be replaced with rb_threadptr_pending_interrupt_enque() */ | ||
| 	EC_JUMP_TAG(ec, state); | ||
|     } | ||
|     return TRUE; | ||
| } | ||
| void | ||
| ... | ... | |
|     } | ||
| } | ||
| void | ||
| /* returns true if a trap handler was run, false otherwise */ | ||
| int | ||
| rb_signal_exec(rb_thread_t *th, int sig) | ||
| { | ||
|     rb_vm_t *vm = GET_VM(); | ||
| ... | ... | |
| 	rb_threadptr_signal_exit(th); | ||
|     } | ||
|     else { | ||
| 	signal_exec(cmd, safe, sig); | ||
| 	return signal_exec(cmd, safe, sig); | ||
|     } | ||
|     return FALSE; | ||
| } | ||
| static sighandler_t | ||
| thread.c | ||
|---|---|---|
|     }; \ | ||
| } while(0) | ||
| /* | ||
|  * returns true if this thread was spuriously interrupted, false otherwise | ||
|  * (e.g. hit by Thread#run or ran a Ruby-level Signal.trap handler) | ||
|  */ | ||
| #define RUBY_VM_CHECK_INTS_BLOCKING(ec) vm_check_ints_blocking(ec) | ||
| static inline void | ||
| static inline int | ||
| vm_check_ints_blocking(rb_execution_context_t *ec) | ||
| { | ||
|     rb_thread_t *th = rb_ec_thread_ptr(ec); | ||
|     if (LIKELY(rb_threadptr_pending_interrupt_empty_p(th))) { | ||
| 	if (LIKELY(!RUBY_VM_INTERRUPTED_ANY(ec))) return; | ||
| 	if (LIKELY(!RUBY_VM_INTERRUPTED_ANY(ec))) return FALSE; | ||
|     } | ||
|     else { | ||
| 	th->pending_interrupt_queue_checked = 0; | ||
| 	RUBY_VM_SET_INTERRUPT(ec); | ||
|     } | ||
|     rb_threadptr_execute_interrupts(th, 1); | ||
|     return rb_threadptr_execute_interrupts(th, 1); | ||
| } | ||
| static int | ||
| ... | ... | |
| { | ||
|     enum rb_thread_status prev_status = th->status; | ||
|     enum rb_thread_status status; | ||
|     int woke; | ||
|     status  = fl & SLEEP_DEADLOCKABLE ? THREAD_STOPPED_FOREVER : THREAD_STOPPED; | ||
|     th->status = status; | ||
| ... | ... | |
| 	if (fl & SLEEP_DEADLOCKABLE) { | ||
| 	    th->vm->sleeper--; | ||
| 	} | ||
| 	RUBY_VM_CHECK_INTS_BLOCKING(th->ec); | ||
| 	if (!(fl & SLEEP_SPURIOUS_CHECK)) | ||
| 	woke = vm_check_ints_blocking(th->ec); | ||
| 	if (woke && !(fl & SLEEP_SPURIOUS_CHECK)) | ||
| 	    break; | ||
|     } | ||
|     th->status = prev_status; | ||
| ... | ... | |
| { | ||
|     struct timespec end; | ||
|     enum rb_thread_status prev_status = th->status; | ||
|     int woke; | ||
|     getclockofday(&end); | ||
|     timespec_add(&end, &ts); | ||
| ... | ... | |
|     RUBY_VM_CHECK_INTS_BLOCKING(th->ec); | ||
|     while (th->status == THREAD_STOPPED) { | ||
| 	native_sleep(th, &ts); | ||
| 	RUBY_VM_CHECK_INTS_BLOCKING(th->ec); | ||
| 	if (!(fl & SLEEP_SPURIOUS_CHECK)) | ||
| 	woke = vm_check_ints_blocking(th->ec); | ||
| 	if (woke && !(fl & SLEEP_SPURIOUS_CHECK)) | ||
| 	    break; | ||
| 	if (timespec_update_expire(&ts, &end)) | ||
| 	    break; | ||
| ... | ... | |
|     return interrupt & (rb_atomic_t)~ec->interrupt_mask; | ||
| } | ||
| MJIT_FUNC_EXPORTED void | ||
| MJIT_FUNC_EXPORTED int | ||
| rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing) | ||
| { | ||
|     rb_atomic_t interrupt; | ||
|     int postponed_job_interrupt = 0; | ||
|     int ret = FALSE; | ||
|     if (th->ec->raised_flag) return; | ||
|     if (th->ec->raised_flag) return ret; | ||
|     while ((interrupt = threadptr_get_interrupts(th)) != 0) { | ||
| 	int sig; | ||
| ... | ... | |
| 	    } | ||
| 	    th->status = THREAD_RUNNABLE; | ||
| 	    while ((sig = rb_get_next_signal()) != 0) { | ||
| 		rb_signal_exec(th, sig); | ||
| 		ret |= rb_signal_exec(th, sig); | ||
| 	    } | ||
| 	    th->status = prev_status; | ||
| 	} | ||
| ... | ... | |
| 	if (pending_interrupt && threadptr_pending_interrupt_active_p(th)) { | ||
| 	    VALUE err = rb_threadptr_pending_interrupt_deque(th, blocking_timing ? INTERRUPT_ON_BLOCKING : INTERRUPT_NONE); | ||
| 	    thread_debug("rb_thread_execute_interrupts: %"PRIdVALUE"\n", err); | ||
|             ret = TRUE; | ||
| 	    if (err == Qundef) { | ||
| 		/* no error */ | ||
| ... | ... | |
| 	    rb_thread_schedule_limits(limits_us); | ||
| 	} | ||
|     } | ||
|     return ret; | ||
| } | ||
| void | ||
| vm_core.h | ||
|---|---|---|
| VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt); | ||
| int rb_signal_buff_size(void); | ||
| void rb_signal_exec(rb_thread_t *th, int sig); | ||
| int rb_signal_exec(rb_thread_t *th, int sig); | ||
| void rb_threadptr_check_signal(rb_thread_t *mth); | ||
| void rb_threadptr_signal_raise(rb_thread_t *th, int sig); | ||
| void rb_threadptr_signal_exit(rb_thread_t *th); | ||
| void rb_threadptr_execute_interrupts(rb_thread_t *, int); | ||
| int rb_threadptr_execute_interrupts(rb_thread_t *, int); | ||
| void rb_threadptr_interrupt(rb_thread_t *th); | ||
| void rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th); | ||
| void rb_threadptr_pending_interrupt_clear(rb_thread_t *th); | ||
| -  | ||