Bug #15310 ยป 0001-thread_pthread.c-close-race-from-UBF_TIMER-and-non-G.patch
| configure.ac | ||
|---|---|---|
| AC_CHECK_FUNCS(sigaction) | ||
| AC_CHECK_FUNCS(sigaltstack) | ||
| AC_CHECK_FUNCS(sigprocmask) | ||
| AC_CHECK_FUNCS(sigqueue) | ||
| AC_CHECK_FUNCS(sinh) | ||
| AC_CHECK_FUNCS(spawnv) | ||
| AC_CHECK_FUNCS(symlink) | ||
| thread.c | ||
|---|---|---|
|     } | ||
| } | ||
| /* async-signal-safe */ | ||
| static void | ||
| timer_thread_function(void) | ||
| { | ||
|     volatile rb_execution_context_t *ec; | ||
|     /* for time slice */ | ||
|     /* for time slice, this relies on GC for grace period */ | ||
|     ec = ACCESS_ONCE(rb_execution_context_t *, | ||
|                      ruby_current_execution_context_ptr); | ||
|     if (ec) RUBY_VM_SET_TIMER_INTERRUPT(ec); | ||
| thread_pthread.c | ||
|---|---|---|
| #if defined(SIGVTALRM) && !defined(__CYGWIN__) | ||
| #  define USE_UBF_LIST 1 | ||
| static LIST_HEAD(ubf_list_head); | ||
| static rb_nativethread_lock_t ubf_list_lock = RB_NATIVETHREAD_LOCK_INIT; | ||
| #endif | ||
| /* | ||
| ... | ... | |
| static pthread_key_t ruby_native_thread_key; | ||
| #if defined(HAVE_SIGACTION) && defined(USE_UBF_LIST) | ||
| static void | ||
| null_func(int i) | ||
| vtalrm_func(int sig, siginfo_t *info, void *ctx) | ||
| { | ||
|     /* null */ | ||
|     /* | ||
|      * if triggered by UBF_TIMER, force running thread to call | ||
|      * ubf_wakeup_all_threads via gvl_yield | ||
|      */ | ||
|     if (info && info->si_ptr == &ubf_list_head) | ||
|         timer_thread_function(); | ||
| } | ||
| #else /* do any platforms have pthreads, SIGVTALRM, but no sigaction? */ | ||
| static void vtalrm_func(int sig) { /* noop */ } | ||
| #endif /* HAVE_SIGACTION && USE_UBF_LIST */ | ||
| static rb_thread_t * | ||
| ruby_thread_from_native(void) | ||
| ... | ... | |
|     th->thread_id = pthread_self(); | ||
|     fill_thread_id_str(th); | ||
|     native_thread_init(th); | ||
|     posix_signal(SIGVTALRM, null_func); | ||
| #if defined(HAVE_SIGACTION) && defined(USE_UBF_LIST) | ||
|     { | ||
|         struct sigaction sa; | ||
|         sigemptyset(&sa.sa_mask); | ||
|         sa.sa_sigaction = vtalrm_func; | ||
|         sa.sa_flags = SA_SIGINFO; | ||
|         if (sigaction(SIGVTALRM, &sa, 0) != 0) | ||
|             rb_async_bug_errno("sigaction", errno); | ||
|     } | ||
| #else | ||
|     posix_signal(SIGVTALRM, vtalrm_func); | ||
| #endif | ||
| } | ||
| static void | ||
| ... | ... | |
| } | ||
| #ifdef USE_UBF_LIST | ||
| static LIST_HEAD(ubf_list_head); | ||
| static rb_nativethread_lock_t ubf_list_lock = RB_NATIVETHREAD_LOCK_INIT; | ||
| static void | ||
| ubf_list_atfork(void) | ||
| ... | ... | |
|     if (setup_communication_pipe_internal(timer_pthread.low) < 0) | ||
|         return; | ||
|     err = pthread_create(&timer_pthread.thid, 0, timer_pthread_fn, GET_VM()); | ||
|     err = pthread_create(&timer_pthread.thid, 0, timer_pthread_fn, 0); | ||
|     if (!err) | ||
|         timer_pthread.owner = current; | ||
|     else | ||
| ... | ... | |
|     sev.sigev_notify = SIGEV_SIGNAL; | ||
|     sev.sigev_signo = SIGVTALRM; | ||
|     sev.sigev_value.sival_ptr = &timer_posix; | ||
|     sev.sigev_value.sival_ptr = &ubf_list_head; | ||
|     if (!timer_create(UBF_TIMER_CLOCK, &sev, &timer_posix.timerid)) | ||
|         timer_posix.owner = current; | ||
|     else | ||
| ... | ... | |
| } | ||
| #if UBF_TIMER == UBF_TIMER_PTHREAD | ||
| static void | ||
| timer_pthread_sigqueue(rb_pid_t pid, int sig) | ||
| { | ||
| #if defined(HAVE_SIGQUEUE) && defined(HAVE_SIGACTION) | ||
|     union sigval sv; | ||
|     sv.sival_ptr = &ubf_list_head; | ||
|     if (sigqueue(pid, sig, sv) != 0) | ||
|         rb_async_bug_errno("sigqueue", errno); | ||
| #else | ||
|     kill(pid, sig); | ||
| #endif | ||
| } | ||
| static void * | ||
| timer_pthread_fn(void *p) | ||
| timer_pthread_fn(void *ignore) | ||
| { | ||
|     rb_vm_t *vm = p; | ||
|     pthread_t main_thread_id = vm->main_thread->thread_id; | ||
|     rb_pid_t pid = getpid(); | ||
|     struct pollfd pfd; | ||
|     int timeout = -1; | ||
| ... | ... | |
|         (void)consume_communication_pipe(pfd.fd); | ||
|         if (system_working > 0 && ATOMIC_CAS(timer_pthread.armed, 1, 1)) { | ||
|             pthread_kill(main_thread_id, SIGVTALRM); | ||
|             timer_pthread_sigqueue(pid, SIGVTALRM); | ||
|             if (rb_signal_buff_size() || !ubf_threads_empty()) { | ||
|                 timeout = TIME_QUANTUM_MSEC; | ||
| -  | ||