2008-10-24 Hans Boehm <Hans.Boehm@hp.com>
authorhboehm <hboehm>
Sat, 25 Oct 2008 00:13:19 +0000 (00:13 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 17:06:43 +0000 (21:06 +0400)
(Partially based loosely on patch from Ivan Maidanski)
* win32_threads.c (GC_may_be_in_stack): New.  (GC_Thread_Rep):
Add last_stack_min.  (GC_push_stack_for): Use last_stack_min.
(GC_get_next_stack): Add limit argument, use_last_stack_min.
(GC_suspend): make stack_base assignment conditional.
* dyn_load.c (win32 GC_cod_add_roots): Pass limit to
GC_get_next_stack.
* configure_atomic_ops.sh: Remove.
* build_atomic_ops.sh, build_atomic_ops.sh.cygwin, doc/README.win32,
Makefile.direct: Partially support build directories whose path
name contains blanks.
* Makefile.am: Support new files (build_atomic_ops.sh,
build_atomic_ops.sh.cygwin)
* Makefile.in: Regenerate.

ChangeLog
Makefile.am
Makefile.direct
Makefile.in
build_atomic_ops.sh [new file with mode: 0755]
build_atomic_ops.sh.cygwin [new file with mode: 0755]
dyn_load.c
win32_threads.c

index 6aee5a4..bf82898 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-10-24  Hans Boehm <Hans.Boehm@hp.com>
+       (Partially based loosely on patch from Ivan Maidanski)
+       * win32_threads.c (GC_may_be_in_stack): New.  (GC_Thread_Rep):
+       Add last_stack_min.  (GC_push_stack_for): Use last_stack_min.
+       (GC_get_next_stack): Add limit argument, use_last_stack_min.
+       (GC_suspend): make stack_base assignment conditional.
+       * dyn_load.c (win32 GC_cod_add_roots): Pass limit to
+       GC_get_next_stack.
+       * configure_atomic_ops.sh: Remove.
+       * build_atomic_ops.sh, build_atomic_ops.sh.cygwin, doc/README.win32,
+       Makefile.direct: Partially support build directories whose path
+       name contains blanks.
+       * Makefile.am: Support new files (build_atomic_ops.sh,
+       build_atomic_ops.sh.cygwin)
+       * Makefile.in: Regenerate.
+
 2008-10-21  Hans Boehm <Hans.Boehm@hp.com> (Really Ivan Maidanski)
        * include/private/gc_locks.h, include/private/gc_pmark.h,
        include/private/gc_priv.h, include/private/gcconfig.h,
index 5565a53..fb658e2 100644 (file)
@@ -164,7 +164,7 @@ EXTRA_DIST += README.QUICK
 EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE \
     OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE        \
     Makefile.direct Makefile.dj        Makefile.DLLs SMakefile.amiga \
-    WCC_MAKEFILE configure_atomic_ops.sh \
+    WCC_MAKEFILE build_atomic_ops.sh build_atomic_ops.sh.cygwin \
     NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
     NT_X64_THREADS_MAKEFILE
 
index a9327a6..06cb899 100644 (file)
@@ -403,8 +403,7 @@ OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
                 PCR-Makefile SMakefile.amiga Makefile.DLLs \
                 digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
                 NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
-                configure_atomic_ops.sh
-#      Makefile and Makefile.direct are copies of each other.
+                build_atomic_ops.sh build_atomic_ops.sh.cygwin 
 
 OTHER_FILES= Makefile setjmp_t.c callprocs \
            MacProjects.sit.hqx MacOS.c \
@@ -438,8 +437,7 @@ all: gc.a gctest
 # if AO_INSTALL_DIR doesn't exist, we assume that it is pointing to
 # the default location, and we need to build
 $(AO_INSTALL_DIR): 
-       CC=$(CC) $(srcdir)/configure_atomic_ops.sh
-       cd $(AO_SRC_DIR); $(MAKE) CC=$(CC) install
+       CC=$(CC) MAKE=$(MAKE) $(srcdir)/build_atomic_ops.sh
 
 LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
 
index b0e3839..3272cba 100644 (file)
@@ -465,12 +465,13 @@ SUBDIRS =
 EXTRA_DIST = gc_cpp.cpp README.QUICK BCC_MAKEFILE NT_MAKEFILE \
        NT_THREADS_MAKEFILE OS2_MAKEFILE PCR-Makefile digimars.mak \
        EMX_MAKEFILE Makefile.direct Makefile.dj Makefile.DLLs \
-       SMakefile.amiga WCC_MAKEFILE configure_atomic_ops.sh \
-       NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
-       NT_X64_THREADS_MAKEFILE add_gc_prefix.c gcname.c if_mach.c \
-       if_not_there.c hpux_test_and_clear.s gc.mak MacOS.c \
-       MacProjects.sit.hqx mach_dep.c setjmp_t.c threadlibs.c \
-       AmigaOS.c Mac_files/datastart.c Mac_files/dataend.c \
+       SMakefile.amiga WCC_MAKEFILE build_atomic_ops.sh \
+       build_atomic_ops.sh.cygwin NT_STATIC_THREADS_MAKEFILE \
+       NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
+       add_gc_prefix.c gcname.c if_mach.c if_not_there.c \
+       hpux_test_and_clear.s gc.mak MacOS.c MacProjects.sit.hqx \
+       mach_dep.c setjmp_t.c threadlibs.c AmigaOS.c \
+       Mac_files/datastart.c Mac_files/dataend.c \
        Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
        include/private/msvc_dbg.h msvc_dbg.c libatomic_ops-1.2 \
        libtool.m4 cord/cordbscs.c cord/cordtest.c cord/de.c \
diff --git a/build_atomic_ops.sh b/build_atomic_ops.sh
new file mode 100755 (executable)
index 0000000..4f74053
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+P=`pwd`/libatomic_ops-install
+cd libatomic_ops-*[0-9]
+./configure --prefix=$P
+$MAKE CC=$CC install
diff --git a/build_atomic_ops.sh.cygwin b/build_atomic_ops.sh.cygwin
new file mode 100755 (executable)
index 0000000..0c24e33
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# We install through the temporary directory in case pwd contains spaces,
+# which otherwise breaks the build machinery.
+# This is a gross hack and probably breaks incremental rebuilds
+mkdir libatomic_ops-install
+P=`pwd`
+Q=`mktemp -d`
+ln -s "$P" $Q/dir
+cd $Q/dir/libatomic_ops-*[0-9]
+./configure --prefix=$Q/dir/libatomic_ops-install
+$MAKE CC=$CC install
+cd /
+rm $Q/dir
+rmdir $Q
index cf409dc..7c758ef 100644 (file)
@@ -699,7 +699,9 @@ void GC_register_dynamic_libraries(void)
   extern GC_bool GC_is_heap_base (ptr_t p);
 
 # ifdef GC_WIN32_THREADS
-    extern void GC_get_next_stack(char *start, char **lo, char **hi);
+    extern void GC_get_next_stack(char *start, char * limit, char **lo,
+                                 char **hi);
+
     void GC_cond_add_roots(char *base, char * limit)
     {
       char * curr_base = base;
@@ -708,9 +710,10 @@ void GC_register_dynamic_libraries(void)
    
       if (base == limit) return;
       for(;;) {
-         GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
+         GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi, limit);
          if (next_stack_lo >= limit) break;
-         GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
+         if (next_stack_lo > curr_base)
+           GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
          curr_base = next_stack_hi;
       }
       if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
index 229e6be..c122998 100644 (file)
@@ -158,6 +158,8 @@ void GC_init_parallel(void);
 
 STATIC DWORD GC_main_thread = 0;
 
+#define ADDR_LIMIT ((ptr_t)(word)-1)
+
 struct GC_Thread_Rep {
   union {
     AO_t tm_in_use;    /* Updated without lock.                */
@@ -181,6 +183,8 @@ struct GC_Thread_Rep {
   ptr_t stack_base;    /* The cold end of the stack.   */
                        /* 0 ==> entry not valid.       */
                        /* !in_use ==> stack_base == 0  */
+  ptr_t last_stack_min;        /* Last known minimum (hottest) address */
+                       /* in stack or ADDR_LIMIT if unset      */
   GC_bool suspended;
 
 # ifdef GC_PTHREADS
@@ -387,6 +391,7 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
        GC_err_printf("Last error code: %d\n", last_error);
        ABORT("DuplicateHandle failed");
   }
+  me -> last_stack_min = ADDR_LIMIT;
   me -> stack_base = sb -> mem_base;
   /* Up until this point, GC_push_all_stacks considers this thread     */
   /* invalid.                                                          */
@@ -702,8 +707,9 @@ void GC_suspend(GC_thread t)
     DWORD exitCode; 
     if (GetExitCodeThread(t -> handle, &exitCode) &&
         exitCode != STILL_ACTIVE) {
-      t -> stack_base = 0; /* prevent stack from being pushed */
-#     ifndef GC_PTHREADS
+#     ifdef GC_PTHREADS
+       t -> stack_base = 0; /* prevent stack from being pushed */
+#     else
         /* this breaks pthread_join on Cygwin, which is guaranteed to  */
         /* only see user pthreads                                     */
        GC_ASSERT(GC_win32_dll_threads);
@@ -808,6 +814,10 @@ void GC_start_world(void)
 #   define GC_get_stack_min(s) \
         ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
 # else
+    /* Probe stack memory region (starting at "s") to find out its     */
+    /* lowest address (i.e. stack top).                                        */
+    /* S must be a mapped address inside the region, NOT the first     */
+    /* unmapped address.                                               */
     static ptr_t GC_get_stack_min(ptr_t s)
     {
        ptr_t bottom;
@@ -820,6 +830,15 @@ void GC_start_world(void)
                 && !(info.Protect & PAGE_GUARD));
        return(bottom);
     }
+
+    /* Return true if the page at s has protections appropriate        */
+    /* for a stack page.                                       */
+    static GC_bool GC_may_be_in_stack(ptr_t s)
+    {
+       MEMORY_BASIC_INFORMATION info;
+       VirtualQuery(s, &info, sizeof(info));
+       return (info.Protect & PAGE_READWRITE) && !(info.Protect & PAGE_GUARD);
+    }
 # endif
 
 STATIC void GC_push_stack_for(GC_thread thread)
@@ -880,11 +899,25 @@ STATIC void GC_push_stack_for(GC_thread thread)
 #       endif
       } /* ! current thread */
 
-      stack_min = GC_get_stack_min(thread->stack_base);
+      /* If got sp value seems to be correct (at least, less than the  */
+      /* bottom of the stack) then do its further validation by quick  */
+      /* probing the memory region at it.                              */
+      /* Set stack_min to the lowest address in the thread stack,      */
+      /* taking advantage of the old value to avoid slow traversals    */
+      /* of large stacks.                                              */
+      if (thread -> last_stack_min == ADDR_LIMIT) {
+       stack_min = GC_get_stack_min(thread -> stack_base);
+      } else {
+        if (GC_may_be_in_stack(thread -> last_stack_min)) {
+          stack_min = GC_get_stack_min(thread -> last_stack_min);
+       } else {
+         stack_min = GC_get_stack_min(thread -> stack_base);
+       }
+      }
+      thread -> last_stack_min = stack_min;
 
       if (sp >= stack_min && sp < thread->stack_base) {
-#       if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \
-           || DEBUG_CYGWIN_THREADS
+#       ifdef DEBUG_THREADS
          GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
                    sp, thread -> stack_base, thread -> id, me);
 #       endif
@@ -947,42 +980,79 @@ void GC_push_all_stacks(void)
     ABORT("Collecting from unknown thread.");
 }
 
-void GC_get_next_stack(char *start, char **lo, char **hi)
+/* Find stack with the lowest address which overlaps the       */
+/* interval [start, limit).                                    */
+/* Return stack bounds in *lo and *hi.  If no such stack       */
+/* is found, both *hi and *lo will be set to an address        */
+/* higher than limit.                                          */
+void GC_get_next_stack(char *start, char *limit,
+                      char **lo, char **hi)
 {
     int i;
-#   define ADDR_LIMIT (char *)(-1L)
-    char * current_min = ADDR_LIMIT;
+    char * current_min = ADDR_LIMIT;  /* Least in-range stack base     */
+    ptr_t *plast_stack_min = NULL;    /* Address of last_stack_min     */
+                                     /* field for thread corresponding */
+                                     /* to current_min.                */
 
-    if (GC_win32_dll_threads) {
-      LONG my_max = GC_get_max_thread_index();
+    /* First set current_min, ignoring limit. */
+      if (GC_win32_dll_threads) {
+        LONG my_max = GC_get_max_thread_index();
   
-      for (i = 0; i <= my_max; i++) {
-       ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
-
-       if (0 != s && s > start && s < current_min) {
-           current_min = s;
-       }
-      }
-    } else {
-      for (i = 0; i < THREAD_TABLE_SZ; i++) {
-       GC_thread t;
-
-        for (t = GC_threads[i]; t != 0; t = t -> next) {
-         ptr_t s = (ptr_t)(t -> stack_base);
+        for (i = 0; i <= my_max; i++) {
+         ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
 
          if (0 != s && s > start && s < current_min) {
+           /* Update address of last_stack_min. */
+           plast_stack_min = (ptr_t * /* no volatile */)
+                               &dll_thread_table[i].last_stack_min;
            current_min = s;
          }
         }
+      } else {
+        for (i = 0; i < THREAD_TABLE_SZ; i++) {
+         GC_thread t;
+
+          for (t = GC_threads[i]; t != 0; t = t -> next) {
+           ptr_t s = t -> stack_base;
+
+           if (0 != s && s > start && s < current_min) {
+             /* Update address of last_stack_min. */
+             plast_stack_min = &t -> last_stack_min;
+             current_min = s;
+           }
+          }
+        }
       }
-    }
+
     *hi = current_min;
     if (current_min == ADDR_LIMIT) {
        *lo = ADDR_LIMIT;
        return;
     }
-    *lo = GC_get_stack_min(current_min);
-    if (*lo < start) *lo = start;
+
+    GC_ASSERT(current_min > start);
+
+    if (current_min > limit && !GC_may_be_in_stack(limit)) {
+      /* Skip the rest since the memory region at limit address is not */
+      /* a stack (so the lowest address of the found stack would be    */
+      /* above the limit value anyway).                                        */
+      *lo = ADDR_LIMIT;
+      return;
+    }
+    
+    /* Get the minimum address of the found stack by probing its memory        */
+    /* region starting from the last known minimum (if set).           */
+      if (*plast_stack_min == ADDR_LIMIT
+        || !GC_may_be_in_stack(*plast_stack_min)) {
+        /* Unsafe to start from last value.    */
+        *lo = GC_get_stack_min(current_min-1);
+      } else {
+        /* Use last value value to optimize search for min address */
+       *lo = GC_get_stack_min(*plast_stack_min);
+      }
+
+    /* Remember current stack_min value. */
+      *plast_stack_min = *lo;
 }
 
 #ifndef GC_PTHREADS