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;
|
||
-
|