Project

General

Profile

Bug #15310 ยป 0001-thread_pthread.c-close-race-from-UBF_TIMER-and-non-G.patch

normalperson (Eric Wong), 11/16/2018 02:30 AM

View differences:

configure.ac
1908 1908
AC_CHECK_FUNCS(sigaction)
1909 1909
AC_CHECK_FUNCS(sigaltstack)
1910 1910
AC_CHECK_FUNCS(sigprocmask)
1911
AC_CHECK_FUNCS(sigqueue)
1911 1912
AC_CHECK_FUNCS(sinh)
1912 1913
AC_CHECK_FUNCS(spawnv)
1913 1914
AC_CHECK_FUNCS(symlink)
thread.c
4238 4238
    }
4239 4239
}
4240 4240

  
4241
/* async-signal-safe */
4241 4242
static void
4242 4243
timer_thread_function(void)
4243 4244
{
4244 4245
    volatile rb_execution_context_t *ec;
4245 4246

  
4246
    /* for time slice */
4247
    /* for time slice, this relies on GC for grace period */
4247 4248
    ec = ACCESS_ONCE(rb_execution_context_t *,
4248 4249
                     ruby_current_execution_context_ptr);
4249 4250
    if (ec) RUBY_VM_SET_TIMER_INTERRUPT(ec);
thread_pthread.c
46 46

  
47 47
#if defined(SIGVTALRM) && !defined(__CYGWIN__)
48 48
#  define USE_UBF_LIST 1
49
static LIST_HEAD(ubf_list_head);
50
static rb_nativethread_lock_t ubf_list_lock = RB_NATIVETHREAD_LOCK_INIT;
49 51
#endif
50 52

  
51 53
/*
......
542 544

  
543 545
static pthread_key_t ruby_native_thread_key;
544 546

  
547
#if defined(HAVE_SIGACTION) && defined(USE_UBF_LIST)
545 548
static void
546
null_func(int i)
549
vtalrm_func(int sig, siginfo_t *info, void *ctx)
547 550
{
548
    /* null */
551
    /*
552
     * if triggered by UBF_TIMER, force running thread to call
553
     * ubf_wakeup_all_threads via gvl_yield
554
     */
555
    if (info && info->si_ptr == &ubf_list_head)
556
        timer_thread_function();
549 557
}
558
#else /* do any platforms have pthreads, SIGVTALRM, but no sigaction? */
559
static void vtalrm_func(int sig) { /* noop */ }
560
#endif /* HAVE_SIGACTION && USE_UBF_LIST */
550 561

  
551 562
static rb_thread_t *
552 563
ruby_thread_from_native(void)
......
578 589
    th->thread_id = pthread_self();
579 590
    fill_thread_id_str(th);
580 591
    native_thread_init(th);
581
    posix_signal(SIGVTALRM, null_func);
592
#if defined(HAVE_SIGACTION) && defined(USE_UBF_LIST)
593
    {
594
        struct sigaction sa;
595

  
596
        sigemptyset(&sa.sa_mask);
597
        sa.sa_sigaction = vtalrm_func;
598
        sa.sa_flags = SA_SIGINFO;
599
        if (sigaction(SIGVTALRM, &sa, 0) != 0)
600
            rb_async_bug_errno("sigaction", errno);
601
    }
602
#else
603
    posix_signal(SIGVTALRM, vtalrm_func);
604
#endif
582 605
}
583 606

  
584 607
static void
......
1269 1292
}
1270 1293

  
1271 1294
#ifdef USE_UBF_LIST
1272
static LIST_HEAD(ubf_list_head);
1273
static rb_nativethread_lock_t ubf_list_lock = RB_NATIVETHREAD_LOCK_INIT;
1274 1295

  
1275 1296
static void
1276 1297
ubf_list_atfork(void)
......
1677 1698
    if (setup_communication_pipe_internal(timer_pthread.low) < 0)
1678 1699
        return;
1679 1700

  
1680
    err = pthread_create(&timer_pthread.thid, 0, timer_pthread_fn, GET_VM());
1701
    err = pthread_create(&timer_pthread.thid, 0, timer_pthread_fn, 0);
1681 1702
    if (!err)
1682 1703
        timer_pthread.owner = current;
1683 1704
    else
......
1700 1721

  
1701 1722
    sev.sigev_notify = SIGEV_SIGNAL;
1702 1723
    sev.sigev_signo = SIGVTALRM;
1703
    sev.sigev_value.sival_ptr = &timer_posix;
1724
    sev.sigev_value.sival_ptr = &ubf_list_head;
1704 1725
    if (!timer_create(UBF_TIMER_CLOCK, &sev, &timer_posix.timerid))
1705 1726
        timer_posix.owner = current;
1706 1727
    else
......
2084 2105
}
2085 2106

  
2086 2107
#if UBF_TIMER == UBF_TIMER_PTHREAD
2108
static void
2109
timer_pthread_sigqueue(rb_pid_t pid, int sig)
2110
{
2111
#if defined(HAVE_SIGQUEUE) && defined(HAVE_SIGACTION)
2112
    union sigval sv;
2113

  
2114
    sv.sival_ptr = &ubf_list_head;
2115
    if (sigqueue(pid, sig, sv) != 0)
2116
        rb_async_bug_errno("sigqueue", errno);
2117
#else
2118
    kill(pid, sig);
2119
#endif
2120
}
2121

  
2087 2122
static void *
2088
timer_pthread_fn(void *p)
2123
timer_pthread_fn(void *ignore)
2089 2124
{
2090
    rb_vm_t *vm = p;
2091
    pthread_t main_thread_id = vm->main_thread->thread_id;
2125
    rb_pid_t pid = getpid();
2092 2126
    struct pollfd pfd;
2093 2127
    int timeout = -1;
2094 2128

  
......
2100 2134
        (void)consume_communication_pipe(pfd.fd);
2101 2135

  
2102 2136
        if (system_working > 0 && ATOMIC_CAS(timer_pthread.armed, 1, 1)) {
2103
            pthread_kill(main_thread_id, SIGVTALRM);
2137
            timer_pthread_sigqueue(pid, SIGVTALRM);
2104 2138

  
2105 2139
            if (rb_signal_buff_size() || !ubf_threads_empty()) {
2106 2140
                timeout = TIME_QUANTUM_MSEC;
2107
-