$(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
# 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
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
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
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
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;
|| 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) {
/* 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. */
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();
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();
/* clean since nothing can point to an */
/* unmarked object. */
GC_read_dirty();
- GC_incremental = TRUE;
out:
UNLOCK();
+ } else {
+ GC_init();
}
+# else
+ GC_init();
# endif
}
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);
if (GC_stderr == NULL) {
GC_stderr = stderr;
}
+ if (GC_log == NULL) {
+ GC_log = stderr;
+ }
}
#endif
#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)
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,
done = TRUE;
}
-# endif
+# endif /* GWW_VDB */
GC_bool GC_wnt = FALSE;
/* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
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)
result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
if (result == (ptr_t)(-1)) result = 0;
}
+ out:
# ifdef IRIX5
__UNLOCK_MALLOC();
# endif
/*
* 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);
}