ruby-changes:51888
From: normal <ko1@a...>
Date: Sun, 29 Jul 2018 19:15:17 +0900 (JST)
Subject: [ruby-changes:51888] normal:r64102 (trunk): thread_pthread.c: clear altstacks in thread cache at GVL destruction
normal 2018-07-29 19:15:11 +0900 (Sun, 29 Jul 2018) New Revision: 64102 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64102 Log: thread_pthread.c: clear altstacks in thread cache at GVL destruction Otherwise, an altstack may live past ObjectSpace destruction and xfree-ing the altstack will segfault. [ruby-core:85621] [Feature #14487] Modified files: trunk/thread_pthread.c trunk/vm_core.h Index: thread_pthread.c =================================================================== --- thread_pthread.c (revision 64101) +++ thread_pthread.c (revision 64102) @@ -46,6 +46,7 @@ void rb_native_cond_wait(rb_nativethread https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L46 void rb_native_cond_initialize(rb_nativethread_cond_t *cond); void rb_native_cond_destroy(rb_nativethread_cond_t *cond); static void rb_thread_wakeup_timer_thread_low(void); +static void clear_thread_cache_altstack(void); #define TIMER_THREAD_MASK (1) #define TIMER_THREAD_SLEEPY (2|TIMER_THREAD_MASK) @@ -66,6 +67,12 @@ static struct { https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L67 } timer_thread; #define TIMER_THREAD_CREATED_P() (timer_thread.created != 0) +#ifdef HAVE_SCHED_YIELD +#define native_thread_yield() (void)sched_yield() +#else +#define native_thread_yield() ((void)0) +#endif + #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \ defined(CLOCK_REALTIME) && defined(CLOCK_MONOTONIC) && \ defined(HAVE_CLOCK_GETTIME) @@ -182,6 +189,7 @@ gvl_destroy(rb_vm_t *vm) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L189 rb_native_cond_destroy(&vm->gvl.switch_cond); rb_native_cond_destroy(&vm->gvl.cond); rb_native_mutex_destroy(&vm->gvl.lock); + clear_thread_cache_altstack(); } #if defined(HAVE_WORKING_FORK) @@ -367,11 +375,6 @@ native_cond_timeout(rb_nativethread_cond https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L375 #define native_cleanup_push pthread_cleanup_push #define native_cleanup_pop pthread_cleanup_pop -#ifdef HAVE_SCHED_YIELD -#define native_thread_yield() (void)sched_yield() -#else -#define native_thread_yield() ((void)0) -#endif #if defined(SIGVTALRM) && !defined(__CYGWIN__) #define USE_UBF_LIST 1 @@ -452,7 +455,7 @@ native_thread_destroy(rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L455 } #if USE_THREAD_CACHE -static rb_thread_t *register_cached_thread_and_wait(void); +static rb_thread_t *register_cached_thread_and_wait(void *); #endif #if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP @@ -855,14 +858,13 @@ thread_start_func_1(void *th_ptr) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L858 #endif } #if USE_THREAD_CACHE - if (1) { - /* cache thread */ - if ((th = register_cached_thread_and_wait()) != 0) { - goto thread_start; - } + /* cache thread */ + if ((th = register_cached_thread_and_wait(RB_ALTSTACK(altstack))) != 0) { + goto thread_start; } -#endif +#else RB_ALTSTACK_FREE(altstack); +#endif return 0; } @@ -870,6 +872,7 @@ struct cached_thread_entry { https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L872 rb_nativethread_cond_t cond; rb_nativethread_id_t thread_id; rb_thread_t *th; + void *altstack; struct list_node node; }; @@ -896,12 +899,13 @@ thread_cache_reset(void) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L899 #endif static rb_thread_t * -register_cached_thread_and_wait(void) +register_cached_thread_and_wait(void *altstack) { struct timespec end = { THREAD_CACHE_TIME, 0 }; struct cached_thread_entry entry; rb_native_cond_initialize(&entry.cond); + entry.altstack = altstack; entry.th = NULL; entry.thread_id = pthread_self(); end = native_cond_timeout(&entry.cond, end); @@ -919,6 +923,9 @@ register_cached_thread_and_wait(void) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L923 rb_native_mutex_unlock(&thread_cache_lock); rb_native_cond_destroy(&entry.cond); + if (!entry.th) { + RB_ALTSTACK_FREE(entry.altstack); + } return entry.th; } @@ -949,6 +956,22 @@ use_cached_thread(rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L956 return 0; } +static void +clear_thread_cache_altstack(void) +{ +#if USE_THREAD_CACHE + struct cached_thread_entry *entry; + + rb_native_mutex_lock(&thread_cache_lock); + list_for_each(&cached_thread_head, entry, node) { + void MAYBE_UNUSED(*altstack) = entry->altstack; + entry->altstack = 0; + RB_ALTSTACK_FREE(altstack); + } + rb_native_mutex_unlock(&thread_cache_lock); +#endif +} + static int native_thread_create(rb_thread_t *th) { Index: vm_core.h =================================================================== --- vm_core.h (revision 64101) +++ vm_core.h (revision 64102) @@ -123,9 +123,11 @@ https://github.com/ruby/ruby/blob/trunk/vm_core.h#L123 void *rb_register_sigaltstack(void); # define RB_ALTSTACK_INIT(var) var = rb_register_sigaltstack() # define RB_ALTSTACK_FREE(var) xfree(var) +# define RB_ALTSTACK(var) var #else /* noop */ # define RB_ALTSTACK_INIT(var) # define RB_ALTSTACK_FREE(var) +# define RB_ALTSTACK(var) (0) #endif /*****************/ -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/