[Gc] Re: Virtual dirty bits for Windows

Ben Hutchings ben.hutchings at businesswebsoftware.com
Tue Nov 23 04:52:37 PST 2004


I wrote:
> I've now tried enabling incremental collection in our (multithreaded) 
> program on Windows and unfortunately it does not work.  The program 
> crashes, apparently due to objects being erroneously collected and 
> cleared.  The GC test program also crashes if built if optimisations are 
> enabled and the GC is dynamically linked and multithreading is enabled, 
> but it succeeds if any of these is not the case.
> 
> I've also attempted a virtual dirty bit implementation based on 
> GetWriteWatch, but that fails similarly.  I've attached a patch (against 
> something resembling version 6.1) for your inspection, in case there's 
> an obvious bug in what I've written.

The bug was in testing the result of GetWriteWatch.  Evidently having 
more dirty pages than can be recorded in the output buffer is not 
reported as a failure, and does result in the buffer being filled and 
the returned pages being marked clean.  So one must loop whenever the 
returned page count is the maximum.

I've attached patches against versions 6.3 and 7.0alpha1, which both 
pass the tests (the latter in combination with my previously-posted 
patches).

Ben.
-------------- next part --------------
diff -u gc7.0alpha1/os_dep.c.orig gc7.0alpha1/os_dep.c
--- gc7.0alpha1/os_dep.c.orig	Wed Nov  3 20:44:49 2004
+++ gc7.0alpha1/os_dep.c	Mon Nov 22 18:18:02 2004
@@ -1652,6 +1652,9 @@
 	/* increased fragmentation.  But better alternatives	*/
 	/* would require effort.				*/
         result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
+#                                     ifdef GWW_VDB
+                                        MEM_WRITE_WATCH |
+#                                     endif
     				      MEM_COMMIT | MEM_RESERVE,
     				      PAGE_EXECUTE_READWRITE);
     }
@@ -2017,7 +2020,7 @@
 
 /*
  * Routines for accessing dirty  bits on virtual pages.
- * There are five ways to maintain this information:
+ * There are six ways to maintain this information:
  * DEFAULT_VDB:	A simple dummy implementation that treats every page
  *		as possibly dirty.  This makes incremental collection
  *		useless, but the implementation is still correct.
@@ -2046,9 +2049,118 @@
  *		call from doing so.  It is the clients responsibility to
  *		make sure that other system calls are similarly protected
  *		or write only to the stack.
+ * GWW_VDB:     Use the Win32 GetWriteWatch functions, if available, to
+ *              read dirty bits.  In case it is not available (because we
+ *              are running on Windows 95, Windows 2000 or earlier),
+ *              MPROTECT_VDB or DEFAULT_VDB must be defined, specifying a
+ *              fallback strategy.
  */
 GC_bool GC_dirty_maintained = FALSE;
 
+#if defined(PROC_VDB) || defined(GWW_VDB)
+
+/* Add all pages in pht2 to pht1 */
+void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
+{
+    register int i;
+    
+    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
+}
+
+#endif
+
+#ifdef GWW_VDB
+
+# ifndef _BASETSD_H_
+    typedef ULONG * PULONG_PTR;
+# endif
+  typedef UINT (WINAPI * PGetWriteWatch)(
+    DWORD, PVOID, SIZE_T, PVOID*, PULONG_PTR, PULONG);
+  static PGetWriteWatch pGetWriteWatch;
+
+# define GC_GWW_BUF_LEN 1024
+  static PVOID gww_buf[GC_GWW_BUF_LEN];
+
+# define GC_GWW_INITIALIZED (pGetWriteWatch != NULL)
+
+  static void GC_gww_dirty_init(void)
+  {
+    pGetWriteWatch = (PGetWriteWatch)
+      GetProcAddress(GetModuleHandle("kernel32.dll"), "GetWriteWatch");
+  }
+
+  static void GC_gww_read_dirty(void)
+  {
+    if (pGetWriteWatch != NULL) {
+      word i;
+
+      BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
+
+      for (i = 0; i != GC_n_heap_sects; ++i) {
+        DWORD count;
+
+        do {
+          PVOID * pages, * pages_end;
+          DWORD page_size;
+
+          pages = gww_buf;
+          count = GC_GWW_BUF_LEN;
+          /*
+           * GetWriteWatch is documented as returning non-zero when it fails,
+           * but the documentation doesn't explicitly say why it would fail or
+           * what its behaviour will be if it fails.  If there are more dirty
+           * pages than will fit in the buffer, this is not treated as a
+           * failure; we must check the page count in the loop condition.
+           */
+          if (pGetWriteWatch(WRITE_WATCH_FLAG_RESET,
+                             GC_heap_sects[i].hs_start,
+                             GC_heap_sects[i].hs_bytes,
+                             pages,
+                             &count,
+                             &page_size) != 0)
+              goto fail;
+
+          pages_end = pages + count;
+          while (pages != pages_end) {
+            struct hblk * h = (struct hblk *) *pages++;
+            struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
+            do
+              set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+            while (++h < h_end);
+          }
+        } while (count == GC_GWW_BUF_LEN);
+      }
+
+      GC_or_pages(GC_written_pages, GC_grungy_pages);
+      return;
+    }
+
+  fail:
+    GC_err_printf("GC_gww_read_dirty fell back to marking all pages dirty\n");
+    memset(GC_grungy_pages, 0xff, sizeof(page_hash_table));
+    memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+  }
+
+  GC_bool GC_gww_page_was_dirty(struct hblk * h)
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+  }
+
+  GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
+  }
+
+# else /* !GWW_VDB */
+
+#   define GC_GWW_INITIALIZED FALSE
+#   define GC_gww_dirty_init()
+#   define GC_gww_read_dirty()
+#   define GC_gww_page_was_dirty(h) TRUE
+#   define GC_gww_page_was_ever_dirty(h) TRUE
+
+# endif /* GWW_VDB */
+
 # ifdef DEFAULT_VDB
 
 /* All of the following assume the allocation lock is held, and	*/
@@ -2062,13 +2174,16 @@
 {
     if (GC_print_stats == VERBOSE)
       GC_log_printf("Initializing DEFAULT_VDB...\n");
+    GC_gww_dirty_init();
     GC_dirty_maintained = TRUE;
 }
 
 /* Retrieve system dirty bits for heap to a local buffer.	*/
 /* Restore the systems notion of which pages are dirty.		*/
 void GC_read_dirty(void)
-{}
+{
+    GC_gww_read_dirty();
+}
 
 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer?	*/
 /* If the actual page size is different, this returns TRUE if any	*/
@@ -2077,7 +2192,7 @@
 /*ARGSUSED*/
 GC_bool GC_page_was_dirty(struct hblk *h)
 {
-    return(TRUE);
+    return GC_gww_page_was_dirty(h);
 }
 
 /*
@@ -2091,7 +2206,7 @@
 /*ARGSUSED*/
 GC_bool GC_page_was_ever_dirty(struct hblk *h)
 {
-    return(TRUE);
+    return GC_gww_page_was_ever_dirty(h);
 }
 
 /* Reset the n pages starting at h to "was never dirty" status.	*/
@@ -2569,12 +2684,15 @@
       }
 #   endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
 #   if defined(MSWIN32)
-      GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
-      if (GC_old_segv_handler != NULL) {
-	if (GC_print_stats == VERBOSE)
-          GC_log_printf("Replaced other UnhandledExceptionFilter\n");
-      } else {
+      GC_gww_dirty_init();
+      if (!GC_GWW_INITIALIZED) {
+        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
+        if (GC_old_segv_handler != NULL) {
+	  if (GC_print_stats == VERBOSE)
+            GC_log_printf("Replaced other UnhandledExceptionFilter\n");
+        } else {
           GC_old_segv_handler = SIG_DFL;
+        }
       }
 #   endif
 }
@@ -2658,17 +2776,25 @@
 /* bits while this is happenning (as in GC_enable_incremental).		*/
 void GC_read_dirty(void)
 {
-    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
-          (sizeof GC_dirty_pages));
-    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
-    GC_protect_heap();
+    if (GC_GWW_INITIALIZED) {
+      GC_gww_read_dirty();
+    } else {
+      BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
+            (sizeof GC_dirty_pages));
+      BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
+      GC_protect_heap();
+    }
 }
 
 GC_bool GC_page_was_dirty(struct hblk *h)
 {
-    register word index = PHT_HASH(h);
+    if (GC_GWW_INITIALIZED) {
+      return GC_gww_page_was_dirty(h);
+    } else {
+      register word index = PHT_HASH(h);
     
-    return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+      return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+    }
 }
 
 /*
@@ -2802,7 +2928,10 @@
 /*ARGSUSED*/
 GC_bool GC_page_was_ever_dirty(struct hblk *h)
 {
-    return(TRUE);
+    if (GC_GWW_INITIALIZED)
+      return GC_gww_page_was_ever_dirty(h);
+    else
+      return(TRUE);
 }
 
 /* Reset the n pages starting at h to "was never dirty" status.	*/
@@ -2855,15 +2984,7 @@
 	(GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
 #endif
 
-/* Add all pages in pht2 to pht1 */
-void GC_or_pages(pgae_hash_table pht1, page_hash_table pht2)
-{
-    register int i;
-    
-    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
-}
-
-int GC_proc_fd;
+<int GC_proc_fd;
 
 void GC_dirty_init(void)
 {
diff -u gc7.0alpha1/include/private/gc_priv.h.orig gc7.0alpha1/include/private/gc_priv.h
--- gc7.0alpha1/include/private/gc_priv.h.orig	Tue Nov  9 06:02:30 2004
+++ gc7.0alpha1/include/private/gc_priv.h	Mon Nov 22 18:11:44 2004
@@ -889,7 +889,7 @@
         /* Stubborn object pages that were changes before last call to	*/
 	/* GC_read_changed.						*/
 # endif
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || defined(GWW_VDB)
     page_hash_table _grungy_pages; /* Pages that were dirty at last 	   */
 				     /* GC_read_dirty.			   */
 # endif
@@ -897,7 +897,7 @@
     volatile page_hash_table _dirty_pages;	
 			/* Pages dirtied since last GC_read_dirty. */
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
     page_hash_table _written_pages;	/* Pages ever dirtied	*/
 # endif
 # ifdef LARGE_CONFIG
@@ -1002,13 +1002,13 @@
 # define GC_excl_table GC_arrays._excl_table
 # define GC_all_nils GC_arrays._all_nils
 # define GC_top_index GC_arrays._top_index
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || defined(GWW_VDB)
 #   define GC_grungy_pages GC_arrays._grungy_pages
 # endif
 # ifdef MPROTECT_VDB
 #   define GC_dirty_pages GC_arrays._dirty_pages
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
 #   define GC_written_pages GC_arrays._written_pages
 # endif
 # define GC_composite_in_use GC_arrays._composite_in_use
diff -u gc7.0alpha1/include/private/gcconfig.h.orig gc7.0alpha1/include/private/gcconfig.h
--- gc7.0alpha1/include/private/gcconfig.h.orig	Wed Nov  3 19:48:52 2004
+++ gc7.0alpha1/include/private/gcconfig.h	Mon Nov 22 18:11:44 2004
@@ -1073,9 +1073,8 @@
 #	define OS_TYPE "MSWIN32"
 		/* STACKBOTTOM and DATASTART are handled specially in 	*/
 		/* os_dep.c.						*/
-#       ifndef __WATCOMC__
-#	  define MPROTECT_VDB
-#	endif
+#       define GWW_VDB
+#       define DEFAULT_VDB
 #       define DATAEND  /* not needed */
 #   endif
 #   ifdef MSWINCE
diff -u gc7.0alpha1/tests/test.c.orig gc7.0alpha1/tests/test.c
--- gc7.0alpha1/tests/test.c.orig	Tue Nov  9 06:10:15 2004
+++ gc7.0alpha1/tests/test.c	Mon Nov 22 18:11:44 2004
@@ -1512,7 +1512,7 @@
 #   endif
     GC_INIT();	/* Only needed on a few platforms.	*/
     (void) GC_set_warn_proc(warn_proc);
-#   if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
+#   if (defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(GWW_VDB)) \
           && !defined(MAKE_BACK_GRAPH)
       GC_enable_incremental();
       (void) GC_printf("Switched to incremental mode\n");
@@ -1652,8 +1652,8 @@
     HANDLE win_thr_h;
 # endif
   DWORD thread_id;
+  GC_init();
   GC_enable_incremental();
-  GC_init();
   InitializeCriticalSection(&incr_cs);
   (void) GC_set_warn_proc(warn_proc);
 # ifdef MSWINCE
-------------- next part --------------
diff -u gc6.3/os_dep.c.orig gc6.3/os_dep.c
--- gc6.3/os_dep.c.orig	Wed Jul  7 20:16:28 2004
+++ gc6.3/os_dep.c	Mon Nov 22 18:06:15 2004
@@ -1683,6 +1683,9 @@
 	/* increased fragmentation.  But better alternatives	*/
 	/* would require effort.				*/
         result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
+#                                     ifdef GWW_VDB
+                                        MEM_WRITE_WATCH |
+#                                     endif
     				      MEM_COMMIT | MEM_RESERVE,
     				      PAGE_EXECUTE_READWRITE);
     }
@@ -2053,7 +2056,7 @@
 
 /*
  * Routines for accessing dirty  bits on virtual pages.
- * We plan to eventually implement four strategies for doing so:
+ * We implement five strategies for doing so:
  * DEFAULT_VDB:	A simple dummy implementation that treats every page
  *		as possibly dirty.  This makes incremental collection
  *		useless, but the implementation is still correct.
@@ -2070,9 +2073,119 @@
  *		call from doing so.  It is the clients responsibility to
  *		make sure that other system calls are similarly protected
  *		or write only to the stack.
+ * GWW_VDB:     Use the Win32 GetWriteWatch functions, if available, to
+ *              read dirty bits.  In case it is not available (because we
+ *              are running on Windows 95, Windows 2000 or earlier),
+ *              MPROTECT_VDB or DEFAULT_VDB must be defined, specifying a
+ *              fallback strategy.
  */
 GC_bool GC_dirty_maintained = FALSE;
 
+#if defined(PROC_VDB) || defined(GWW_VDB)
+
+/* Add all pages in pht2 to pht1 */
+void GC_or_pages(pht1, pht2)
+page_hash_table pht1, pht2;
+{
+    register int i;
+    
+    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
+}
+
+#endif
+
+#ifdef GWW_VDB
+
+# ifndef _BASETSD_H_
+    typedef ULONG * PULONG_PTR;
+# endif
+  typedef UINT (WINAPI * PGetWriteWatch)(
+    DWORD, PVOID, SIZE_T, PVOID*, PULONG_PTR, PULONG);
+  static PGetWriteWatch pGetWriteWatch;
+
+# define GC_GWW_BUF_LEN 1024
+  static PVOID gww_buf[GC_GWW_BUF_LEN];
+
+# define GC_GWW_INITIALIZED (pGetWriteWatch != NULL)
+
+  static void GC_gww_dirty_init(void)
+  {
+    pGetWriteWatch = (PGetWriteWatch)
+      GetProcAddress(GetModuleHandle("kernel32.dll"), "GetWriteWatch");
+  }
+
+  static void GC_gww_read_dirty(void)
+  {
+    if (pGetWriteWatch != NULL) {
+      word i;
+
+      BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
+
+      for (i = 0; i != GC_n_heap_sects; ++i) {
+        DWORD count;
+
+        do {
+          PVOID * pages, * pages_end;
+          DWORD page_size;
+
+          pages = gww_buf;
+          count = GC_GWW_BUF_LEN;
+          /*
+           * GetWriteWatch is documented as returning non-zero when it fails,
+           * but the documentation doesn't explicitly say why it would fail or
+           * what its behaviour will be if it fails.  If there are more dirty
+           * pages than will fit in the buffer, this is not treated as a
+           * failure; we must check the page count in the loop condition.
+           */
+          if (pGetWriteWatch(WRITE_WATCH_FLAG_RESET,
+                             GC_heap_sects[i].hs_start,
+                             GC_heap_sects[i].hs_bytes,
+                             pages,
+                             &count,
+                             &page_size) != 0)
+              goto fail;
+
+          pages_end = pages + count;
+          while (pages != pages_end) {
+            struct hblk * h = (struct hblk *) *pages++;
+            struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
+            do
+              set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+            while (++h < h_end);
+          }
+        } while (count == GC_GWW_BUF_LEN);
+      }
+
+      GC_or_pages(GC_written_pages, GC_grungy_pages);
+      return;
+    }
+
+  fail:
+    GC_err_printf0("GC_gww_read_dirty fell back to marking all pages dirty\n");
+    memset(GC_grungy_pages, 0xff, sizeof(page_hash_table));
+    memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+  }
+
+  GC_bool GC_gww_page_was_dirty(struct hblk * h)
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+  }
+
+  GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
+  }
+
+# else /* !GWW_VDB */
+
+#   define GC_GWW_INITIALIZED FALSE
+#   define GC_gww_dirty_init()
+#   define GC_gww_read_dirty()
+#   define GC_gww_page_was_dirty(h) TRUE
+#   define GC_gww_page_was_ever_dirty(h) TRUE
+
+# endif /* GWW_VDB */
+
 # ifdef DEFAULT_VDB
 
 /* All of the following assume the allocation lock is held, and	*/
@@ -2087,13 +2200,16 @@
 #   ifdef PRINTSTATS
       GC_printf0("Initializing DEFAULT_VDB...\n");
 #   endif
+    GC_gww_dirty_init();
     GC_dirty_maintained = TRUE;
 }
 
 /* Retrieve system dirty bits for heap to a local buffer.	*/
 /* Restore the systems notion of which pages are dirty.		*/
 void GC_read_dirty()
-{}
+{
+    GC_gww_read_dirty();
+}
 
 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer?	*/
 /* If the actual page size is different, this returns TRUE if any	*/
@@ -2103,7 +2219,7 @@
 GC_bool GC_page_was_dirty(h)
 struct hblk *h;
 {
-    return(TRUE);
+    return GC_gww_page_was_dirty(h);
 }
 
 /*
@@ -2118,7 +2234,7 @@
 GC_bool GC_page_was_ever_dirty(h)
 struct hblk *h;
 {
-    return(TRUE);
+    return GC_gww_page_was_ever_dirty(h);
 }
 
 /* Reset the n pages starting at h to "was never dirty" status.	*/
@@ -2769,13 +2885,16 @@
       }
 #   endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
 #   if defined(MSWIN32)
-      GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
-      if (GC_old_segv_handler != NULL) {
-#	ifdef PRINTSTATS
-          GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
-#	endif
-      } else {
+      GC_gww_dirty_init();
+      if (!GC_GWW_INITIALIZED) {
+        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
+        if (GC_old_segv_handler != NULL) {
+#         ifdef PRINTSTATS
+            GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
+#         endif
+        } else {
           GC_old_segv_handler = SIG_DFL;
+        }
       }
 #   endif
 }
@@ -2859,18 +2978,26 @@
 /* bits while this is happenning (as in GC_enable_incremental).		*/
 void GC_read_dirty()
 {
-    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
-          (sizeof GC_dirty_pages));
-    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
-    GC_protect_heap();
+    if (GC_GWW_INITIALIZED) {
+      GC_gww_read_dirty();
+    } else {
+      BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
+            (sizeof GC_dirty_pages));
+      BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
+      GC_protect_heap();
+    }
 }
 
 GC_bool GC_page_was_dirty(h)
 struct hblk * h;
 {
-    register word index = PHT_HASH(h);
+    if (GC_GWW_INITIALIZED) {
+      return GC_gww_page_was_dirty(h);
+    } else {
+      register word index = PHT_HASH(h);
     
-    return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+      return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+    }
 }
 
 /*
@@ -3018,7 +3145,10 @@
 GC_bool GC_page_was_ever_dirty(h)
 struct hblk *h;
 {
-    return(TRUE);
+    if (GC_GWW_INITIALIZED)
+      return GC_gww_page_was_ever_dirty(h);
+    else
+      return(TRUE);
 }
 
 /* Reset the n pages starting at h to "was never dirty" status.	*/
@@ -3072,15 +3202,6 @@
 #   define PAGE_IS_FRESH(h) \
 	(GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
 #endif
-
-/* Add all pages in pht2 to pht1 */
-void GC_or_pages(pht1, pht2)
-page_hash_table pht1, pht2;
-{
-    register int i;
-    
-    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
-}
 
 int GC_proc_fd;
 
diff -u gc6.3/include/private/gc_priv.h.orig gc6.3/include/private/gc_priv.h
--- gc6.3/include/private/gc_priv.h.orig	Thu Jul  8 18:20:08 2004
+++ gc6.3/include/private/gc_priv.h	Mon Nov 22 18:03:40 2004
@@ -951,7 +951,7 @@
         /* Stubborn object pages that were changes before last call to	*/
 	/* GC_read_changed.						*/
 # endif
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || defined(GWW_VDB)
     page_hash_table _grungy_pages; /* Pages that were dirty at last 	   */
 				     /* GC_read_dirty.			   */
 # endif
@@ -959,7 +959,7 @@
     VOLATILE page_hash_table _dirty_pages;	
 			/* Pages dirtied since last GC_read_dirty. */
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
     page_hash_table _written_pages;	/* Pages ever dirtied	*/
 # endif
 # ifdef LARGE_CONFIG
@@ -1056,13 +1056,13 @@
 # define GC_excl_table GC_arrays._excl_table
 # define GC_all_nils GC_arrays._all_nils
 # define GC_top_index GC_arrays._top_index
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || defined(GWW_VDB)
 #   define GC_grungy_pages GC_arrays._grungy_pages
 # endif
 # ifdef MPROTECT_VDB
 #   define GC_dirty_pages GC_arrays._dirty_pages
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
 #   define GC_written_pages GC_arrays._written_pages
 # endif
 # ifdef GATHERSTATS
diff -u gc6.3/include/private/gcconfig.h.orig gc6.3/include/private/gcconfig.h
--- gc6.3/include/private/gcconfig.h.orig	Thu May  6 00:10:54 2004
+++ gc6.3/include/private/gcconfig.h	Mon Nov 22 18:03:40 2004
@@ -1157,9 +1157,8 @@
 #	define OS_TYPE "MSWIN32"
 		/* STACKBOTTOM and DATASTART are handled specially in 	*/
 		/* os_dep.c.						*/
-#       ifndef __WATCOMC__
-#	  define MPROTECT_VDB
-#	endif
+#       define GWW_VDB
+#       define DEFAULT_VDB
 #       define DATAEND  /* not needed */
 #   endif
 #   ifdef MSWINCE
diff -u gc6.3/tests/test.c.orig gc6.3/tests/test.c
--- gc6.3/tests/test.c.orig	Fri Apr  2 18:29:04 2004
+++ gc6.3/tests/test.c	Mon Nov 22 18:06:52 2004
@@ -1500,7 +1500,7 @@
 #   endif
     GC_INIT();	/* Only needed on a few platforms.	*/
     (void) GC_set_warn_proc(warn_proc);
-#   if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
+#   if (defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(GWW_VDB)) \
           && !defined(MAKE_BACK_GRAPH)
       GC_enable_incremental();
       (void) GC_printf0("Switched to incremental mode\n");
@@ -1640,10 +1640,10 @@
     HANDLE win_thr_h;
 # endif
   DWORD thread_id;
-# if 0
+  GC_init();
+# ifdef MSWIN32
     GC_enable_incremental();
 # endif
-  GC_init();
   InitializeCriticalSection(&incr_cs);
   (void) GC_set_warn_proc(warn_proc);
 # ifdef MSWINCE


More information about the Gc mailing list