From bf75d68aaef8ba0f7ad76ff1f07182cfed283823 Mon Sep 17 00:00:00 2001 From: hboehm Date: Sat, 29 Apr 2006 00:05:26 +0000 Subject: [PATCH] 2006-04-28 Hans Boehm * NT_STATIC_THREADS_MAKEFILE: Assorted cleanups and bug fixes for VC++.net * mark.c (alloc_mark_stack): Recycle old stack only if it doesn't break GWW_VDB. * misc.c: Try to initialize GWW_VDB earlier. Remove seemingly obsolete initialization code. More consistently use GC_LOF_FILE. * os_dep.c (GC_unix_get_mem): Ensure sbrk lock release on Irix, even in the really obscure cases. Fix GetWriteWatch error handling; work around slightly late calls to GC_enable_incremental(). --- NT_STATIC_THREADS_MAKEFILE | 8 ++-- doc/README.changes | 8 ++++ mark.c | 21 +++++++++-- misc.c | 65 ++++++++++++++++++-------------- os_dep.c | 77 ++++++++++++++++++++++++++------------ 5 files changed, 118 insertions(+), 61 deletions(-) diff --git a/NT_STATIC_THREADS_MAKEFILE b/NT_STATIC_THREADS_MAKEFILE index 88cd67d1..6b145603 100644 --- a/NT_STATIC_THREADS_MAKEFILE +++ b/NT_STATIC_THREADS_MAKEFILE @@ -22,7 +22,7 @@ all: gctest.exe cord\de.exe test_cpp.exe $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_WIN32_THREADS $*.c /Fo$*.obj .cpp.obj: - $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS /Fo$*.obj + $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS /Fo$*.obj $(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h @@ -35,7 +35,7 @@ gctest.exe: tests\test.obj gc.lib # and add mapsympe line. # This produces a "GUI" applications that opens no windows and writes to the log file # "gc.log". This is done to make the result runnable under win32s. - $(link) -debug:full -debugtype:cv /MT $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib + $(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib # mapsympe -n -o gctest.sym gctest.exe cord\de_win.rbj: cord\de_win.res @@ -44,11 +44,11 @@ cord\de_win.rbj: cord\de_win.res cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h - $(rc) $(rcvars) -r -fo cord\de_win.res $(cvarsmt) cord\de_win.rc + $(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc # Cord/de is a real win32 gui application. cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib - $(link) -debug:full -debugtype:cv /MT $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs) + $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs) gc_cpp.obj: include\gc_cpp.h include\gc.h diff --git a/doc/README.changes b/doc/README.changes index ff9b5431..e8e4cf5e 100644 --- a/doc/README.changes +++ b/doc/README.changes @@ -2280,6 +2280,9 @@ Since gc6.7: Thomas Klausner.) - Improvements to the HP/UX section of configure.in/configure.ac. (Thanks to Andreas Tobler) + - GC_unix_get_mem could neglect to release the malloc lock on Irix, under + extremely unlikely circumstances. Thanks to Jean-Baptiste Nivois for + some careful code reading. Since gc6.8: - Remove GC_PROTO, VOLATILE, GC_PTR, and GC_CONST. Assume ANSI C compiler @@ -2495,6 +2498,11 @@ Since gc7.0alpha5 are almost certainly already out of date, but better than what we had before. - Fixed some win32 threads bugs, and added support for _beginthreadex. + - Fix zero size thread local allocation so that explicit deallocation + works correctly. + - Removed serious bug in GC_malloc_uncollectable(large size). + - Do not try to do thread-local gcj allocation in incremental mode. There + are races in setting up the descriptor. To do: - REDIRECT_MALLOC and threads combination is getting closer, but currently diff --git a/mark.c b/mark.c index d46c1ac7..10df6749 100644 --- a/mark.c +++ b/mark.c @@ -1173,20 +1173,33 @@ void GC_help_marker(word my_mark_no) static void alloc_mark_stack(size_t n) { mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry)); +# ifdef GWW_VDB + /* Don't recycle a stack segment obtained with the wrong flags. */ + /* Win32 GetWriteWatch requires the right kind of memory. */ + static GC_incremental_at_stack_alloc = 0; + GC_bool recycle_old = (!GC_incremental || GC_incremental_at_stack_alloc); + + GC_incremental_at_stack_alloc = GC_incremental; +# else +# define recycle_old 1 +# endif GC_mark_stack_too_small = FALSE; if (GC_mark_stack_size != 0) { if (new_stack != 0) { - word displ = (word)GC_mark_stack & (GC_page_size - 1); - signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry); + if (recycle_old) { + /* Recycle old space */ + size_t page_offset = (word)GC_mark_stack & (GC_page_size - 1); + size_t size = GC_mark_stack_size * sizeof(struct GC_ms_entry); + size_t displ = 0; - /* Recycle old space */ - if (0 != displ) displ = GC_page_size - displ; + if (0 != page_offset) displ = GC_page_size - page_offset; size = (size - displ) & ~(GC_page_size - 1); if (size > 0) { GC_add_to_heap((struct hblk *) ((word)GC_mark_stack + displ), (word)size); } + } GC_mark_stack = new_stack; GC_mark_stack_size = n; GC_mark_stack_limit = new_stack + n; diff --git a/misc.c b/misc.c index b077de02..6e12e514 100644 --- a/misc.c +++ b/misc.c @@ -627,10 +627,6 @@ void GC_init_inner() || defined(GC_WIN32_THREADS) GC_thr_init(); # endif -# ifdef GC_SOLARIS_THREADS - /* We need dirty bits in order to find live stack sections. */ - GC_dirty_init(); -# endif # if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \ || defined(GC_SOLARIS_THREADS) if (GC_stackbottom == 0) { @@ -674,6 +670,17 @@ void GC_init_inner() /* word should be unsigned */ # endif GC_ASSERT((signed_word)(-1) < (signed_word)0); +# if !defined(SMALL_CONFIG) + if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) { + /* This used to test for !GC_no_win32_dlls. Why? */ + GC_setpagesize(); + /* For GWW_MPROTECT on Win32, this needs to happen before any */ + /* heap memory is allocated. */ + GC_dirty_init(); + GC_ASSERT(GC_bytes_allocd == 0) + GC_incremental = TRUE; + } +# endif /* !SMALL_CONFIG */ /* Add initial guess of root sets. Do this first, since sbrk(0) */ /* might be used. */ @@ -721,17 +728,6 @@ void GC_init_inner() PCR_IL_Unlock(); GC_pcr_install(); # endif -# if !defined(SMALL_CONFIG) - if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) { - GC_ASSERT(!GC_incremental); - GC_setpagesize(); -# ifndef GC_SOLARIS_THREADS - GC_dirty_init(); -# endif - GC_ASSERT(GC_bytes_allocd == 0) - GC_incremental = TRUE; - } -# endif /* !SMALL_CONFIG */ COND_DUMP; /* Get black list set up and/or incremental GC started */ if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner(); @@ -769,16 +765,15 @@ void GC_enable_incremental(void) LOCK(); if (GC_incremental) goto out; GC_setpagesize(); - if (GC_no_win32_dlls) goto out; -# ifndef GC_SOLARIS_THREADS - maybe_install_looping_handler(); /* Before write fault handler! */ - GC_dirty_init(); - if (!GC_dirty_maintained) goto out; -# endif + /* if (GC_no_win32_dlls) goto out; Should be win32S test? */ + maybe_install_looping_handler(); /* Before write fault handler! */ + GC_incremental = TRUE; if (!GC_is_initialized) { GC_init_inner(); + } else { + GC_dirty_init(); } - if (GC_incremental) goto out; + if (!GC_dirty_maintained) goto out; if (GC_dont_gc) { /* Can't easily do it. */ UNLOCK(); @@ -791,10 +786,13 @@ void GC_enable_incremental(void) /* clean since nothing can point to an */ /* unmarked object. */ GC_read_dirty(); - GC_incremental = TRUE; out: UNLOCK(); + } else { + GC_init(); } +# else + GC_init(); # endif } @@ -828,18 +826,23 @@ out: if (GC_stdout == INVALID_HANDLE_VALUE) { return -1; } else if (GC_stdout == 0) { - char logPath[_MAX_PATH + 5]; + char * file_name = GETENV("GC_LOG_FILE"); + char logPath[_MAX_PATH + 5]; + + if (0 == file_name) { # ifdef OLD_WIN32_LOG_FILE strcpy(logPath, LOG_FILE); # else GetModuleFileName(NULL, logPath, _MAX_PATH); strcat(logPath, ".log"); # endif - GC_stdout = CreateFile(logPath, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, - NULL); - if (GC_stdout == INVALID_HANDLE_VALUE) + file_name = logPath; + } + GC_stdout = CreateFile(logPath, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, + NULL); + if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed"); } tmp = WriteFile(GC_stdout, buf, len, &written, NULL); @@ -868,6 +871,9 @@ int GC_tmp; /* Should really be local ... */ if (GC_stderr == NULL) { GC_stderr = stderr; } + if (GC_log == NULL) { + GC_log = stderr; + } } #endif @@ -922,6 +928,7 @@ int GC_write(fd, buf, len) #if defined(MSWIN32) || defined(MSWINCE) + /* FIXME: This is pretty ugly ... */ # define WRITE(f, buf, len) GC_write(buf, len) #else # if defined(OS2) || defined(MACOS) diff --git a/os_dep.c b/os_dep.c index 974c8ed5..2f1fa9ba 100644 --- a/os_dep.c +++ b/os_dep.c @@ -1232,7 +1232,9 @@ void GC_register_data_segments(void) PVOID pages[16]; DWORD count = 16; DWORD page_size; - /* On recent W2K versions, everything may exist, but always fail. */ + /* Check that it actually works. In spite of some */ + /* documentation it actually seems to exist on W2K. */ + /* This test may be unnecessary, but ... */ if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, page, GC_page_size, pages, @@ -1259,7 +1261,7 @@ void GC_register_data_segments(void) done = TRUE; } -# endif +# endif /* GWW_VDB */ GC_bool GC_wnt = FALSE; /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */ @@ -1662,13 +1664,19 @@ ptr_t GC_unix_get_mem(word bytes) ptr_t cur_brk = (ptr_t)sbrk(0); SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1); - if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */ + if ((SBRK_ARG_T)bytes < 0) { + result = 0; /* too big */ + goto out; + } if (lsbs != 0) { - if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0); + if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) { + result = 0; + goto out; + } } # ifdef ADD_HEAP_GUARD_PAGES - /* This is useful for catching severe memory overwrite problems that span */ - /* heap sections. It shouldn't otherwise be turned on. */ + /* This is useful for catching severe memory overwrite problems that */ + /* span heap sections. It shouldn't otherwise be turned on. */ { ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size); if (mprotect(guard, GC_page_size, PROT_NONE) != 0) @@ -1678,6 +1686,7 @@ ptr_t GC_unix_get_mem(word bytes) result = (ptr_t)sbrk((SBRK_ARG_T)bytes); if (result == (ptr_t)(-1)) result = 0; } + out: # ifdef IRIX5 __UNLOCK_MALLOC(); # endif @@ -2160,32 +2169,52 @@ void GC_or_pages(page_hash_table pht1, page_hash_table pht2) /* * 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 + * what its behaviour will be if it fails. + * It does appear to fail, at least on recent W2K instances, if + * the underlying memory was not allocated with the appropriate + * flag. This is common if GC_enable_incremental is called + * shortly after GC initialization. To avoid modifying the + * interface, we silently work around such a failure, it it only + * affects the initial (small) heap allocation. + * 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. + * Since each partial call will reset the status of some + * pages, this should eventually terminate even in the overflow + * case. */ if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET, GC_heap_sects[i].hs_start, GC_heap_sects[i].hs_bytes, pages, &count, - &page_size) != 0) - { - GC_err_printf( - "GC_gww_read_dirty unexpectedly failed: " - "Falling 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)); - return; - } - - 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); + &page_size) != 0) { + static int warn_count = 0; + unsigned j; + struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start; + static struct hblk *last_warned = 0; + unsigned nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes); + + if ( i != 0 && last_warned != start && warn_count++ < 5) { + last_warned = start; + WARN( + "GC_gww_read_dirty unexpectedly failed at %ld: " + "Falling back to marking all pages dirty\n", start); + } + for (j = 0; j < nblocks; ++j) { + word hash = PHT_HASH(start + j); + set_pht_entry_from_index(GC_grungy_pages, hash); + } + count = 1; /* Done with this section. */ + } else /* succeeded */{ + 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); } -- 2.40.0