From: Zoltan Varga Date: Mon, 21 May 2012 23:02:05 +0000 (+0200) Subject: Add alt-stack registration support X-Git-Tag: gc7_6_0~165 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ceae609d3e20822d7818cdef732348053227e1a;p=gc Add alt-stack registration support (Apply commit ff4ec56 from 'mono_libgc' branch.) Fix altstack support in libgc by registering the bounds of the normal stack and the altstack with it. * darwin_stop_world.c (GC_stack_range_for): Add paltstack_lo, paltstack_hi argments; set *paltstack_lo, *paltstack_hi, adjust lo and hi if p->altstack set. * darwin_stop_world.c (GC_push_all_stacks): Declare altstack_lo, altstack_hi local variables; pass &altstack_lo, &altstack_hi to GC_stack_range_for; do not call GC_push_all_stack(lo, hi) and adjust total_size by hi-lo if lo is NULL; call GC_push_all_stack(altstack_lo, altstack_hi) and increment total_size by altstack_hi-altstack_lo if altstack_lo is non-NULL. * include/gc.h (GC_register_altstack): New API function declaration. * include/private/pthread_support.h (GC_Thread_Rep): Add altstack, altstack_size, stack, stack_size fields. * pthread_stop_world.c (GC_push_all_stacks): Adjust hi value if p->altstack set. * pthread_support.c (main_pthread_self, main_stack, main_altstack, main_stack_size, main_altstack_size): New static variables. * pthread_support.c (GC_register_altstack): New function. * pthread_support.c (GC_thr_init): Set altstack, altstack_size, stack, stack_size fields from values saved by GC_register_altstack (if called before GC_thr_init). * win32_threads.c (GC_register_altstack): New function (unimplemented). --- diff --git a/darwin_stop_world.c b/darwin_stop_world.c index 718e2f5c..23979035 100644 --- a/darwin_stop_world.c +++ b/darwin_stop_world.c @@ -129,7 +129,8 @@ GC_API void GC_CALL GC_use_threads_discovery(void) /* Evaluates the stack range for a given thread. Returns the lower */ /* bound and sets *phi to the upper one. */ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p, - GC_bool thread_blocked, mach_port_t my_thread) + GC_bool thread_blocked, mach_port_t my_thread, + ptr_t *paltstack_lo, ptr_t *paltstack_hi) { ptr_t lo; if (thread == my_thread) { @@ -302,6 +303,16 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p, /* p is guaranteed to be non-NULL regardless of GC_query_task_threads. */ *phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end; # endif + + if (p->altstack && lo >= p->altstack && lo <= p->altstack + p->altstack_size) { + *paltstack_lo = lo; + *paltstack_hi = p->altstack + p->altstack_size; + lo = (char*)p->stack; + *phi = (char*)p->stack + p->stack_size; + } else { + *paltstack_lo = NULL; + } + # ifdef DEBUG_THREADS GC_log_printf("Darwin: Stack for thread %p = [%p,%p)\n", (void *)thread, lo, *phi); @@ -312,7 +323,7 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p, GC_INNER void GC_push_all_stacks(void) { int i; - ptr_t lo, hi; + ptr_t lo, hi, altstack_lo, altstack_hi; task_t my_task = current_task(); mach_port_t my_thread = mach_thread_self(); GC_bool found_me = FALSE; @@ -334,10 +345,17 @@ GC_INNER void GC_push_all_stacks(void) for (i = 0; i < (int)listcount; i++) { thread_act_t thread = act_list[i]; - lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread); - GC_ASSERT((word)lo <= (word)hi); - total_size += hi - lo; - GC_push_all_stack(lo, hi); + lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread, + &altstack_lo, &altstack_hi); + if (lo) { + GC_ASSERT((word)lo <= (word)hi); + total_size += hi - lo; + GC_push_all_stack(lo,hi); + } + if (altstack_lo) { + total_size += altstack_hi - altstack_lo; + GC_push_all_stack(altstack_lo,altstack_hi); + } nthreads++; if (thread == my_thread) found_me = TRUE; @@ -355,10 +373,16 @@ GC_INNER void GC_push_all_stacks(void) if ((p->flags & FINISHED) == 0) { thread_act_t thread = (thread_act_t)p->stop_info.mach_thread; lo = GC_stack_range_for(&hi, thread, p, (GC_bool)p->thread_blocked, - my_thread); - GC_ASSERT((word)lo <= (word)hi); - total_size += hi - lo; - GC_push_all_stack_sections(lo, hi, p->traced_stack_sect); + my_thread, &altstack_lo, &altstack_hi); + if (lo) { + GC_ASSERT((word)lo <= (word)hi); + total_size += hi - lo; + GC_push_all_stack_sections(lo, hi, p->traced_stack_sect); + } + if (altstack_lo) { + total_size += altstack_hi - altstack_lo; + GC_push_all_stack(altstack_lo, altstack_hi); + } nthreads++; if (thread == my_thread) found_me = TRUE; diff --git a/include/gc.h b/include/gc.h index a52408af..d33049ec 100644 --- a/include/gc.h +++ b/include/gc.h @@ -1367,6 +1367,12 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */, /* registered with the garbage collector. */ GC_API int GC_CALL GC_thread_is_registered(void); +/* Notify the collector about the stack and the altstack of the current thread */ +/* STACK/STACK_SIZE is used to determine the stack dimensions when a thread is + * suspended while it is on an altstack. + */ +GC_API void GC_register_altstack(void *stack, int stack_size, void *altstack, int altstack_size); + /* Unregister the current thread. Only an explicitly registered */ /* thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS) */ /* is allowed (and required) to call this function. (As a special */ diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h index 525a9aac..c45817d4 100644 --- a/include/private/pthread_support.h +++ b/include/private/pthread_support.h @@ -86,6 +86,10 @@ typedef struct GC_Thread_Rep { ptr_t stack_end; /* Cold end of the stack (except for */ /* main thread). */ + ptr_t altstack; /* The start of the altstack if there is one, NULL otherwise */ + int altstack_size; /* The size of the altstack if there is one */ + ptr_t stack; /* The start of the normal stack */ + int stack_size; /* The size of the normal stack */ # if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK) ptr_t topOfStack; /* Result of GC_FindTopOfStack(0); */ /* valid only if the thread is blocked; */ diff --git a/pthread_stop_world.c b/pthread_stop_world.c index 9d046b4f..600dbdb2 100644 --- a/pthread_stop_world.c +++ b/pthread_stop_world.c @@ -402,6 +402,10 @@ GC_INNER void GC_push_all_stacks(void) (void *)p->id, lo, hi); # endif if (0 == lo) ABORT("GC_push_all_stacks: sp not set!"); + if (p->altstack && lo >= p->altstack && lo <= p->altstack + p->altstack_size) + hi = p->altstack + p->altstack_size; + /* FIXME: Need to scan the normal stack too, but how ? */ + GC_push_all_stack_sections(lo, hi, traced_stack_sect); # ifdef STACK_GROWS_UP total_size += lo - hi; diff --git a/pthread_support.c b/pthread_support.c index 2fca3602..b74a3131 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -658,6 +658,34 @@ GC_API int GC_CALL GC_thread_is_registered(void) return me != NULL; } +static pthread_t main_pthread_self; +static void *main_stack, *main_altstack; +static int main_stack_size, main_altstack_size; + +void GC_register_altstack (void *stack, int stack_size, void *altstack, int altstack_size) +{ + GC_thread thread; + + LOCK(); + thread = (void *)GC_lookup_thread(pthread_self()); + if (thread) { + thread->stack = stack; + thread->stack_size = stack_size; + thread->altstack = altstack; + thread->altstack_size = altstack_size; + } else { + /* + * This happens if we are called before GC_thr_init (). + */ + main_pthread_self = pthread_self (); + main_stack = stack; + main_stack_size = stack_size; + main_altstack = altstack; + main_altstack_size = altstack_size; + } + UNLOCK(); +} + #ifdef CAN_HANDLE_FORK /* Remove all entries from the GC_threads table, except the */ /* one for the current thread. We need to do this in the child */ @@ -1084,6 +1112,12 @@ GC_INNER void GC_thr_init(void) t -> stop_info.stack_ptr = GC_approx_sp(); # endif t -> flags = DETACHED | MAIN_THREAD; + if (pthread_self () == main_pthread_self) { + t->stack = main_stack; + t->stack_size = main_stack_size; + t->altstack = main_altstack; + t->altstack_size = main_altstack_size; + } } # ifndef GC_DARWIN_THREADS diff --git a/win32_threads.c b/win32_threads.c index 400884ad..4b3a7d81 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -601,6 +601,10 @@ GC_API int GC_CALL GC_thread_is_registered(void) return me != NULL; } +void GC_register_altstack (void *stack, int stack_size, void *altstack, int altstack_size) +{ +} + /* Make sure thread descriptor t is not protected by the VDB */ /* implementation. */ /* Used to prevent write faults when the world is (partially) stopped, */