summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.c6
-rw-r--r--include/ruby/internal/interpreter.h2
-rw-r--r--thread.c4
-rw-r--r--thread_none.c7
-rw-r--r--thread_pthread.c32
-rw-r--r--thread_win32.c14
-rw-r--r--vm.c11
-rw-r--r--vm_core.h2
8 files changed, 44 insertions, 34 deletions
diff --git a/eval.c b/eval.c
index aa0eae0872..13f4557862 100644
--- a/eval.c
+++ b/eval.c
@@ -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.
diff --git a/thread.c b/thread.c
index 070d1bbdfa..e7a9d7cd9b 100644
--- a/thread.c
+++ b/thread.c
@@ -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 */
diff --git a/vm.c b/vm.c
index a2a17f8fe7..98e280bf28 100644
--- a/vm.c
+++ b/vm.c
@@ -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>
diff --git a/vm_core.h b/vm_core.h
index 7cd8fa76c5..f1928d1ee2 100644
--- a/vm_core.h
+++ b/vm_core.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);