diff options
-rw-r--r-- | eval.c | 6 | ||||
-rw-r--r-- | include/ruby/internal/interpreter.h | 2 | ||||
-rw-r--r-- | thread.c | 4 | ||||
-rw-r--r-- | thread_none.c | 7 | ||||
-rw-r--r-- | thread_pthread.c | 32 | ||||
-rw-r--r-- | thread_win32.c | 14 | ||||
-rw-r--r-- | vm.c | 11 | ||||
-rw-r--r-- | vm_core.h | 2 |
8 files changed, 44 insertions, 34 deletions
@@ -70,8 +70,6 @@ ruby_setup(void) if (GET_VM()) return 0; - ruby_init_stack((void *)&state); - /* * Disable THP early before mallocs happen because we want this to * affect as many future pages as possible for CoW-friendliness @@ -115,7 +113,6 @@ ruby_options(int argc, char **argv) enum ruby_tag_type state; void *volatile iseq = 0; - ruby_init_stack((void *)&iseq); EC_PUSH_TAG(ec); if ((state = EC_EXEC_TAG()) == TAG_NONE) { SAVE_ROOT_JMPBUF(GET_THREAD(), iseq = ruby_process_options(argc, argv)); @@ -205,7 +202,6 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex) step_0: step++; save_error = ec->errinfo; if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil; - ruby_init_stack(&message); /* exits with failure but silently when an exception raised * here */ @@ -324,14 +320,12 @@ ruby_run_node(void *n) rb_ec_cleanup(ec, (NIL_P(ec->errinfo) ? TAG_NONE : TAG_RAISE)); return status; } - ruby_init_stack((void *)&status); return rb_ec_cleanup(ec, rb_ec_exec_node(ec, n)); } int ruby_exec_node(void *n) { - ruby_init_stack((void *)&n); return rb_ec_exec_node(GET_EC(), n); } diff --git a/include/ruby/internal/interpreter.h b/include/ruby/internal/interpreter.h index 662d39c0ec..a10e7ad2d8 100644 --- a/include/ruby/internal/interpreter.h +++ b/include/ruby/internal/interpreter.h @@ -141,7 +141,7 @@ void ruby_show_copyright(void); * * @param[in] addr A pointer somewhere on the stack, near its bottom. */ -void ruby_init_stack(volatile VALUE *addr); +void ruby_init_stack(void *addr); /** * Initializes the VM and builtin libraries. @@ -522,9 +522,9 @@ static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *); static VALUE rb_thread_to_s(VALUE thread); void -ruby_thread_init_stack(rb_thread_t *th) +ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) { - native_thread_init_stack(th); + native_thread_init_stack(th, local_in_parent_frame); } const VALUE * diff --git a/thread_none.c b/thread_none.c index 4d53d3bf4d..cb35aea708 100644 --- a/thread_none.c +++ b/thread_none.c @@ -139,13 +139,8 @@ ruby_mn_threads_params(void) { } -void -ruby_init_stack(volatile VALUE *addr) -{ -} - static int -native_thread_init_stack(rb_thread_t *th) +native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) { #if defined(__wasm__) && !defined(__EMSCRIPTEN__) th->ec->machine.stack_start = (VALUE *)rb_wasm_stack_get_base(); diff --git a/thread_pthread.c b/thread_pthread.c index 6d2f55a957..58bc49b17c 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1962,9 +1962,8 @@ reserve_stack(volatile char *limit, size_t size) # define reserve_stack(limit, size) ((void)(limit), (void)(size)) #endif -#undef ruby_init_stack -void -ruby_init_stack(volatile VALUE *addr) +static void +native_thread_init_main_thread_stack(void *addr) { native_main_thread.id = pthread_self(); @@ -1987,7 +1986,7 @@ ruby_init_stack(volatile VALUE *addr) if (!native_main_thread.stack_start || STACK_UPPER((VALUE *)(void *)&addr, native_main_thread.stack_start > addr, - native_main_thread.stack_start < addr)) { + native_main_thread.stack_start < (VALUE *)addr)) { native_main_thread.stack_start = (VALUE *)addr; } #endif @@ -2049,10 +2048,16 @@ ruby_init_stack(volatile VALUE *addr) {int err = (expr); if (err) {rb_bug_errno(#expr, err);}} static int -native_thread_init_stack(rb_thread_t *th) +native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) { rb_nativethread_id_t curr = pthread_self(); + if (!native_main_thread.id) { + /* This thread is the first thread, must be the main thread - + * configure the native_main_thread object */ + native_thread_init_main_thread_stack(local_in_parent_frame); + } + if (pthread_equal(curr, native_main_thread.id)) { th->ec->machine.stack_start = native_main_thread.stack_start; th->ec->machine.stack_maxsize = native_main_thread.stack_maxsize; @@ -2064,8 +2069,8 @@ native_thread_init_stack(rb_thread_t *th) size_t size; if (get_stack(&start, &size) == 0) { - uintptr_t diff = (uintptr_t)start - (uintptr_t)&curr; - th->ec->machine.stack_start = (VALUE *)&curr; + uintptr_t diff = (uintptr_t)start - (uintptr_t)local_in_parent_frame; + th->ec->machine.stack_start = (uintptr_t)local_in_parent_frame; th->ec->machine.stack_maxsize = size - diff; } } @@ -2185,8 +2190,19 @@ native_thread_create_dedicated(rb_thread_t *th) static void call_thread_start_func_2(rb_thread_t *th) { - native_thread_init_stack(th); + /* Capture the address of a local in this stack frame to mark the beginning of the + machine stack for this thread. This is required even if we can tell the real + stack beginning from the pthread API in native_thread_init_stack, because + glibc stores some of its own data on the stack before calling into user code + on a new thread, and replacing that data on fiber-switch would break it (see + bug #13887) */ + VALUE stack_start = 0; + VALUE *stack_start_addr = &stack_start; + native_thread_init_stack(th, stack_start_addr); thread_start_func_2(th, th->ec->machine.stack_start); + + /* Ensure that stack_start really was spilled to the stack */ + RB_GC_GUARD(stack_start) } static void * diff --git a/thread_win32.c b/thread_win32.c index bd983e0bd9..af007d5877 100644 --- a/thread_win32.c +++ b/thread_win32.c @@ -581,10 +581,6 @@ rb_native_cond_destroy(rb_nativethread_cond_t *cond) /* */ } -void -ruby_init_stack(volatile VALUE *addr) -{ -} #define CHECK_ERR(expr) \ {if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}} @@ -594,20 +590,20 @@ COMPILER_WARNING_PUSH COMPILER_WARNING_IGNORED(-Wmaybe-uninitialized) #endif static inline SIZE_T -query_memory_basic_info(PMEMORY_BASIC_INFORMATION mi) +query_memory_basic_info(PMEMORY_BASIC_INFORMATION mi, void *local_in_parent_frame) { - return VirtualQuery(mi, mi, sizeof(*mi)); + return VirtualQuery(local_in_parent_frame, mi, sizeof(*mi)); } COMPILER_WARNING_POP static void -native_thread_init_stack(rb_thread_t *th) +native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame) { MEMORY_BASIC_INFORMATION mi; char *base, *end; DWORD size, space; - CHECK_ERR(query_memory_basic_info(&mi)); + CHECK_ERR(query_memory_basic_info(&mi, local_in_parent_frame)); base = mi.AllocationBase; end = mi.BaseAddress; end += mi.RegionSize; @@ -638,7 +634,7 @@ thread_start_func_1(void *th_ptr) rb_thread_t *th = th_ptr; volatile HANDLE thread_id = th->nt->thread_id; - native_thread_init_stack(th); + native_thread_init_stack(th, &th); th->nt->interrupt_event = CreateEvent(0, TRUE, FALSE, 0); /* run */ @@ -54,6 +54,8 @@ int ruby_assert_critical_section_entered = 0; #endif +static void *native_main_thread_stack_top; + VALUE rb_str_concat_literals(size_t, const VALUE*); VALUE vm_exec(rb_execution_context_t *); @@ -4206,7 +4208,8 @@ Init_BareVM(void) th_init(th, 0, vm); rb_ractor_set_current_ec(th->ractor, th->ec); - ruby_thread_init_stack(th); + /* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */ + ruby_thread_init_stack(th, native_main_thread_stack_top); // setup ractor system rb_native_mutex_initialize(&vm->ractor.sync.lock); @@ -4217,6 +4220,12 @@ Init_BareVM(void) #endif } +void +ruby_init_stack(void *addr) +{ + native_main_thread_stack_top = addr; +} + #ifndef _WIN32 #include <unistd.h> #include <sys/mman.h> @@ -1840,7 +1840,7 @@ rb_control_frame_t *rb_vm_get_binding_creatable_next_cfp(const rb_execution_cont VALUE *rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); int rb_vm_get_sourceline(const rb_control_frame_t *); void rb_vm_stack_to_heap(rb_execution_context_t *ec); -void ruby_thread_init_stack(rb_thread_t *th); +void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame); rb_thread_t * ruby_thread_from_native(void); int ruby_thread_set_native(rb_thread_t *th); int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp); |