ruby-changes:52494
From: normal <ko1@a...>
Date: Thu, 13 Sep 2018 05:49:17 +0900 (JST)
Subject: [ruby-changes:52494] normal:r64703 (trunk): share VM stack between threads and fibers if identical in size
normal 2018-09-13 05:49:10 +0900 (Thu, 13 Sep 2018) New Revision: 64703 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64703 Log: share VM stack between threads and fibers if identical in size ec->vm_stack is always allocated with malloc, so stack cache for root fiber (thread stack) and non-root fibers can be shared as long as the size is the same. The purpose of this change is to reduce dependencies on ROOT_FIBER_CONTEXT. [Feature #15095] [Bug #15050] v2: vm.c: fix build with USE_THREAD_DATA_RECYCLE==0 Modified files: trunk/cont.c trunk/internal.h trunk/vm.c Index: internal.h =================================================================== --- internal.h (revision 64702) +++ internal.h (revision 64703) @@ -1915,6 +1915,7 @@ void Init_BareVM(void); https://github.com/ruby/ruby/blob/trunk/internal.h#L1915 void Init_vm_objects(void); PUREFUNC(VALUE rb_vm_top_self(void)); void rb_thread_recycle_stack_release(VALUE *); +VALUE *rb_thread_recycle_stack(size_t); void rb_vm_change_state(void); void rb_vm_inc_const_missing_count(void); const void **rb_vm_get_insns_address_table(void); Index: vm.c =================================================================== --- vm.c (revision 64702) +++ vm.c (revision 64703) @@ -2340,23 +2340,20 @@ vm_init2(rb_vm_t *vm) https://github.com/ruby/ruby/blob/trunk/vm.c#L2340 #define RECYCLE_MAX 64 static VALUE *thread_recycle_stack_slot[RECYCLE_MAX]; static int thread_recycle_stack_count = 0; +#endif /* USE_THREAD_DATA_RECYCLE */ -static VALUE * -thread_recycle_stack(size_t size) +VALUE * +rb_thread_recycle_stack(size_t size) { +#if USE_THREAD_DATA_RECYCLE if (thread_recycle_stack_count > 0) { /* TODO: check stack size if stack sizes are variable */ return thread_recycle_stack_slot[--thread_recycle_stack_count]; } - else { - return ALLOC_N(VALUE, size); - } +#endif /* USE_THREAD_DATA_RECYCLE */ + return ALLOC_N(VALUE, size); } -#else -#define thread_recycle_stack(size) ALLOC_N(VALUE, (size)) -#endif - void rb_thread_recycle_stack_release(VALUE *stack) { @@ -2536,7 +2533,7 @@ th_init(rb_thread_t *th, VALUE self) https://github.com/ruby/ruby/blob/trunk/vm.c#L2533 /* vm_stack_size is word number. * th->vm->default_params.thread_vm_stack_size is byte size. */ size_t size = th->vm->default_params.thread_vm_stack_size / sizeof(VALUE); - ec_set_vm_stack(th->ec, thread_recycle_stack(size), size); + ec_set_vm_stack(th->ec, rb_thread_recycle_stack(size), size); } th->ec->cfp = (void *)(th->ec->vm_stack + th->ec->vm_stack_size); Index: cont.c =================================================================== --- cont.c (revision 64702) +++ cont.c (revision 64703) @@ -1411,13 +1411,20 @@ fiber_init(VALUE fibval, VALUE proc) https://github.com/ruby/ruby/blob/trunk/cont.c#L1411 rb_context_t *cont = &fib->cont; rb_execution_context_t *sec = &cont->saved_ec; rb_thread_t *cth = GET_THREAD(); - size_t fib_stack_size = cth->vm->default_params.fiber_vm_stack_size / sizeof(VALUE); + rb_vm_t *vm = cth->vm; + size_t fib_stack_bytes = vm->default_params.fiber_vm_stack_size; + size_t thr_stack_bytes = vm->default_params.thread_vm_stack_size; + VALUE *vm_stack; /* initialize cont */ cont->saved_vm_stack.ptr = NULL; - ec_set_vm_stack(sec, NULL, 0); - - ec_set_vm_stack(sec, ALLOC_N(VALUE, fib_stack_size), fib_stack_size); + if (fib_stack_bytes == thr_stack_bytes) { + vm_stack = rb_thread_recycle_stack(fib_stack_bytes / sizeof(VALUE)); + } + else { + vm_stack = ruby_xmalloc(fib_stack_bytes); + } + ec_set_vm_stack(sec, vm_stack, fib_stack_bytes / sizeof(VALUE)); sec->cfp = (void *)(sec->vm_stack + sec->vm_stack_size); rb_vm_push_frame(sec, @@ -1758,19 +1765,22 @@ rb_fiber_transfer(VALUE fibval, int argc https://github.com/ruby/ruby/blob/trunk/cont.c#L1765 void rb_fiber_close(rb_fiber_t *fib) { - VALUE *vm_stack = fib->cont.saved_ec.vm_stack; + rb_execution_context_t *ec = &fib->cont.saved_ec; + VALUE *vm_stack = ec->vm_stack; + size_t stack_bytes = ec->vm_stack_size * sizeof(VALUE); + fiber_status_set(fib, FIBER_TERMINATED); - if (fib->cont.type == ROOT_FIBER_CONTEXT) { - rb_thread_recycle_stack_release(vm_stack); + if (stack_bytes == rb_ec_vm_ptr(ec)->default_params.thread_vm_stack_size) { + rb_thread_recycle_stack_release(vm_stack); } else { - ruby_xfree(vm_stack); + ruby_xfree(vm_stack); } - ec_set_vm_stack(&fib->cont.saved_ec, NULL, 0); + ec_set_vm_stack(ec, NULL, 0); #if !FIBER_USE_NATIVE /* should not mark machine stack any more */ - fib->cont.saved_ec.machine.stack_end = NULL; + ec->machine.stack_end = NULL; #endif } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/