]> granicus.if.org Git - gc/commitdiff
Add alt-stack registration support
authorZoltan Varga <vargaz@gmail.com>
Mon, 21 May 2012 23:02:05 +0000 (01:02 +0200)
committerIvan Maidanski <ivmai@mail.ru>
Fri, 24 Jul 2015 18:50:57 +0000 (21:50 +0300)
(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).

darwin_stop_world.c
include/gc.h
include/private/pthread_support.h
pthread_stop_world.c
pthread_support.c
win32_threads.c

index 718e2f5cbe92461e38599dce951984aa824f5f68..23979035176dd43242d22bd2b5f1b5557431e081 100644 (file)
@@ -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;
index a52408af0eb3396d259c279593b74974c8b6da8b..d33049ec87e3cbe9f7bd88c8b553f0a3b11d9879 100644 (file)
@@ -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    */
index 525a9aac2f37340b24f52e0c161df1a276a47dd0..c45817d428797bea1f197ce28a18c8307bcf3de8 100644 (file)
@@ -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; */
index 9d046b4f89b59a17e7a69fb3de1790979756dadf..600dbdb20bed52e7eb67f2a334220b3476bf210f 100644 (file)
@@ -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;
index 2fca3602b62447feee3108582818de72b56d4de3..b74a3131230e5133ef24ed6347f87e03507c97ef 100644 (file)
@@ -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
index 400884ada4df02ecfb3e842a66e5c41af283413d..4b3a7d8125688bf2077e92f5dc5ef6790d92a938 100644 (file)
@@ -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,  */