summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorivmai <ivmai>2009-12-07 17:12:40 +0000
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 21:06:52 +0400
commit176d5bda1e4416a306005d5ee66a902e9db6af6d (patch)
tree52e7c56e61bb91f41a8005e16bc61eccca74cb93
parenta745f0f3f342887988aa9d05c29b2478f0e30101 (diff)
downloadbdwgc-176d5bda1e4416a306005d5ee66a902e9db6af6d.tar.gz
2009-12-07 Ivan Maidanski <ivmai@mail.ru>
* doc/README.macros (GC_READ_ENV_FILE): Document (new macro). * include/private/gc_priv.h (GETENV): Recognize GC_READ_ENV_FILE; declare and use GC_envfile_getenv(). * misc.c (GC_envfile_content, GC_envfile_length): New static variable (only if GC_READ_ENV_FILE). * misc.c (GC_ENVFILE_MAXLEN): New macro (used in GC_envfile_init). * misc.c (GC_envfile_init, GC_envfile_getenv): New function (only if GC_READ_ENV_FILE). * misc.c (GC_init): Call GC_envfile_init() (before using GETENV) if GC_READ_ENV_FILE. * misc.c (GC_init): Move GC_setpagesize() and GC_init_win32() calls to be just before GC_envfile_init() one (since the latter uses GET_MEM). * misc.c (GC_abort): use ExitProcess() (instead of DebugBreak) for WinCE if NO_DEBUGGING; add a comment for DebugBreak() (for WinCE). * mark_rts.c (GC_add_roots_inner): Remove redundant trailing '\n' from the ABORT message. * misc.c (GC_init): Ditto. * os_dep.c (GC_get_main_stack_base, GC_register_data_segments): Ditto. * pthread_stop_world.c (GC_push_all_stacks): Ditto. * pthread_support.c (GC_init_real_syms, start_mark_threads): Ditto.
-rw-r--r--ChangeLog26
-rw-r--r--doc/README.macros9
-rw-r--r--include/private/gc_priv.h29
-rw-r--r--mark_rts.c2
-rw-r--r--misc.c121
-rw-r--r--os_dep.c8
-rw-r--r--pthread_stop_world.c2
-rw-r--r--pthread_support.c6
8 files changed, 171 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index cb64c75c..a3f41826 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2009-12-07 Ivan Maidanski <ivmai@mail.ru>
+
+ * doc/README.macros (GC_READ_ENV_FILE): Document (new macro).
+ * include/private/gc_priv.h (GETENV): Recognize GC_READ_ENV_FILE;
+ declare and use GC_envfile_getenv().
+ * misc.c (GC_envfile_content, GC_envfile_length): New static
+ variable (only if GC_READ_ENV_FILE).
+ * misc.c (GC_ENVFILE_MAXLEN): New macro (used in GC_envfile_init).
+ * misc.c (GC_envfile_init, GC_envfile_getenv): New function (only
+ if GC_READ_ENV_FILE).
+ * misc.c (GC_init): Call GC_envfile_init() (before using GETENV)
+ if GC_READ_ENV_FILE.
+ * misc.c (GC_init): Move GC_setpagesize() and GC_init_win32()
+ calls to be just before GC_envfile_init() one (since the latter
+ uses GET_MEM).
+ * misc.c (GC_abort): use ExitProcess() (instead of DebugBreak) for
+ WinCE if NO_DEBUGGING; add a comment for DebugBreak() (for WinCE).
+ * mark_rts.c (GC_add_roots_inner): Remove redundant trailing '\n'
+ from the ABORT message.
+ * misc.c (GC_init): Ditto.
+ * os_dep.c (GC_get_main_stack_base, GC_register_data_segments):
+ Ditto.
+ * pthread_stop_world.c (GC_push_all_stacks): Ditto.
+ * pthread_support.c (GC_init_real_syms, start_mark_threads):
+ Ditto.
+
2009-12-06 Ivan Maidanski <ivmai@mail.ru>
* win32_threads.c (GC_get_next_stack): Don't define for Cygwin
diff --git a/doc/README.macros b/doc/README.macros
index 2ca74d46..2e5fabb0 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -389,12 +389,19 @@ NO_GETENV Prevents the collector from looking at environment variables.
EMPTY_GETENV_RESULTS Define to workaround a reputed Wine bug in getenv
(getenv() may return an empty string instead of NULL for a missing entry).
+GC_READ_ENV_FILE (win32 only) Read environment variables from the GC "env"
+ file (named as the program name plus ".gc.env" extension). Useful for WinCE
+ targets (which have no getenv()). In the file, every variable is specified
+ in a separate line and the format is as "<name>=<value>" (without spaces).
+ A comment line may start with any character except for the Latin letters,
+ the digits and the underscore ('_'). The file encoding is Latin-1.
+
USE_GLOBAL_ALLOC (Win32 only) Use GlobalAlloc() instead of VirtualAlloc()
to allocate the heap. May be needed to work around a Windows NT/2000 issue.
Incompatible with USE_MUNMAP. See README.win32 for details.
MAKE_BACK_GRAPH Enable GC_PRINT_BACK_HEIGHT environment variable.
- See README.environment for details. Experimental. Limited platform
+ See README.environment for details. Experimental. Limited platform
support. Implies DBG_HDRS_ALL. All allocation should be done using
the debug interface.
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 6442e553..7dbdafa2 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -447,22 +447,21 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
#endif
/* Get environment entry */
-#if !defined(NO_GETENV)
-# if defined(EMPTY_GETENV_RESULTS)
- /* Workaround for a reputed Wine bug. */
- GC_INLINE char * fixed_getenv(const char *name)
- {
- char * tmp = getenv(name);
- if (tmp == 0 || strlen(tmp) == 0)
- return 0;
- return tmp;
- }
-# define GETENV(name) fixed_getenv(name)
-# else
-# define GETENV(name) getenv(name)
-# endif
+#ifdef GC_READ_ENV_FILE
+ GC_INNER char * GC_envfile_getenv(const char *name);
+# define GETENV(name) GC_envfile_getenv(name)
+#elif defined(NO_GETENV)
+# define GETENV(name) NULL
+#elif defined(EMPTY_GETENV_RESULTS)
+ /* Workaround for a reputed Wine bug. */
+ GC_INLINE char * fixed_getenv(const char *name)
+ {
+ char *value = getenv(name);
+ return value != NULL && *value != '\0' ? value : NULL;
+ }
+# define GETENV(name) fixed_getenv(name)
#else
-# define GETENV(name) 0
+# define GETENV(name) getenv(name)
#endif
#if defined(DARWIN)
diff --git a/mark_rts.c b/mark_rts.c
index 8afefdc2..f19093fe 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -226,7 +226,7 @@ void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
}
# endif
if (n_root_sets == MAX_ROOT_SETS) {
- ABORT("Too many root sets\n");
+ ABORT("Too many root sets");
}
GC_static_roots[n_root_sets].r_start = (ptr_t)b;
GC_static_roots[n_root_sets].r_end = (ptr_t)e;
diff --git a/misc.c b/misc.c
index 54978861..931684d9 100644
--- a/misc.c
+++ b/misc.c
@@ -466,6 +466,106 @@ GC_API size_t GC_CALL GC_get_total_bytes(void)
}
#endif /* THREADS */
+#ifdef GC_READ_ENV_FILE
+ /* This works for Win32/WinCE for now. Really useful only for WinCE. */
+ STATIC char *GC_envfile_content = NULL;
+ /* The content of the GC "env" file with CR and */
+ /* LF replaced to '\0'. NULL if the file is */
+ /* missing or empty. Otherwise, always ends */
+ /* with '\0'. */
+ STATIC unsigned GC_envfile_length = 0;
+ /* Length of GC_envfile_content (if non-NULL). */
+
+# ifndef GC_ENVFILE_MAXLEN
+# define GC_ENVFILE_MAXLEN 0x4000
+# endif
+
+ /* The routine initializes GC_envfile_content from the GC "env" file. */
+ STATIC void GC_envfile_init(void)
+ {
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+ HANDLE hFile;
+ char *content;
+ unsigned ofs;
+ unsigned len;
+ DWORD nBytesRead;
+ TCHAR path[_MAX_PATH + 0x10]; /* buffer for path + ext */
+ len = (unsigned)GetModuleFileName(NULL /* hModule */, path,
+ _MAX_PATH + 1);
+ /* If GetModuleFileName() has failed then len is 0. */
+ if (len > 4 && path[len - 4] == (TCHAR)'.') {
+ len -= 4; /* strip executable file extension */
+ }
+ memcpy(&path[len], TEXT(".gc.env"), sizeof(TEXT(".gc.env")));
+ hFile = CreateFile(path, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL /* lpSecurityAttributes */, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL /* hTemplateFile */);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return; /* the file is absent or the operation is failed */
+ len = (unsigned)GetFileSize(hFile, NULL);
+ if (len <= 1 || len >= GC_ENVFILE_MAXLEN) {
+ CloseHandle(hFile);
+ return; /* invalid file length - ignoring the file content */
+ }
+ /* At this execution point, GC_setpagesize() and GC_init_win32() */
+ /* must already be called (for GET_MEM() to work correctly). */
+ content = (char *)GET_MEM(len + 1);
+ if (content == NULL) {
+ CloseHandle(hFile);
+ return; /* allocation failure */
+ }
+ ofs = 0;
+ nBytesRead = (DWORD)-1L;
+ /* Last ReadFile() call should clear nBytesRead on success. */
+ while (ReadFile(hFile, content + ofs, len - ofs + 1, &nBytesRead,
+ NULL /* lpOverlapped */) && nBytesRead != 0) {
+ if ((ofs += nBytesRead) > len)
+ break;
+ }
+ CloseHandle(hFile);
+ if (ofs != len || nBytesRead != 0)
+ return; /* read operation is failed - ignoring the file content */
+ content[ofs] = '\0';
+ while (ofs-- > 0) {
+ if (content[ofs] == '\r' || content[ofs] == '\n')
+ content[ofs] = '\0';
+ }
+ GC_envfile_length = len + 1;
+ GC_envfile_content = content;
+# endif
+ }
+
+ /* This routine scans GC_envfile_content for the specified */
+ /* environment variable (and returns its value if found). */
+ GC_INNER char * GC_envfile_getenv(const char *name)
+ {
+ char *p;
+ char *end_of_content;
+ unsigned namelen;
+# ifndef NO_GETENV
+ p = getenv(name); /* try the standard getenv() first */
+ if (p != NULL)
+ return *p != '\0' ? p : NULL;
+# endif
+ p = GC_envfile_content;
+ if (p == NULL)
+ return NULL; /* "env" file is absent (or empty) */
+ namelen = strlen(name);
+ if (namelen == 0) /* a sanity check */
+ return NULL;
+ for (end_of_content = p + GC_envfile_length;
+ p != end_of_content; p += strlen(p) + 1) {
+ if (strncmp(p, name, namelen) == 0 && *(p += namelen) == '=') {
+ p++; /* the match is found; skip '=' */
+ return *p != '\0' ? p : NULL;
+ }
+ /* If not matching then skip to the next line. */
+ }
+ return NULL; /* no match found */
+ }
+#endif /* GC_READ_ENV_FILE */
+
GC_INNER GC_bool GC_is_initialized = FALSE;
#if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
@@ -570,6 +670,13 @@ GC_API void GC_CALL GC_init(void)
# if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
InitializeCriticalSection(&GC_write_cs);
# endif
+ GC_setpagesize();
+# ifdef MSWIN32
+ GC_init_win32();
+# endif
+# ifdef GC_READ_ENV_FILE
+ GC_envfile_init();
+# endif
# ifndef SMALL_CONFIG
# ifdef GC_PRINT_VERBOSE_STATS
/* This is useful for debugging and profiling on platforms with */
@@ -714,16 +821,12 @@ GC_API void GC_CALL GC_init(void)
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
}
- GC_setpagesize();
GC_exclude_static_roots_inner(beginGC_arrays, endGC_arrays);
GC_exclude_static_roots_inner(beginGC_obj_kinds, endGC_obj_kinds);
# ifdef SEPARATE_GLOBALS
GC_exclude_static_roots_inner(beginGC_objfreelist, endGC_objfreelist);
GC_exclude_static_roots_inner(beginGC_aobjfreelist, endGC_aobjfreelist);
# endif
-# ifdef MSWIN32
- GC_init_win32();
-# endif
# if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
/* If thread stacks are cached, they tend to be scanned in */
@@ -829,9 +932,9 @@ GC_API void GC_CALL GC_init(void)
# ifdef PCR
if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay) {
- ABORT("Can't lock load state\n");
+ ABORT("Can't lock load state");
} else if (PCR_IL_Unlock() != PCR_ERes_okay) {
- ABORT("Can't unlock load state\n");
+ ABORT("Can't unlock load state");
}
PCR_IL_Unlock();
GC_pcr_install();
@@ -1260,12 +1363,16 @@ GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
/* about threads. */
for(;;) {}
}
+ if (!msg) return; /* to suppress compiler warnings in ABORT callers. */
# if defined(MSWIN32) && defined(NO_DEBUGGING)
/* A more user-friendly abort after showing fatal message. */
- if (msg) /* to suppress compiler warnings in ABORT callers. */
_exit(-1); /* exit on error without running "at-exit" callbacks */
+# elif defined(MSWINCE) && defined(NO_DEBUGGING)
+ ExitProcess(-1);
# elif defined(MSWIN32) || defined(MSWINCE)
DebugBreak();
+ /* Note that on a WinCE box, this could be silently */
+ /* ignored (i.e., the program is not aborted). */
# else
(void) abort();
# endif
diff --git a/os_dep.c b/os_dep.c
index a525283c..62e13f17 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -828,7 +828,7 @@ ptr_t GC_get_main_stack_base(void)
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
GC_err_printf("DosGetInfoBlocks failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
return((ptr_t)(ptib -> tib_pstacklimit));
}
@@ -1339,18 +1339,18 @@ void GC_register_data_segments(void)
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
GC_err_printf("DosGetInfoBlocks failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
module_handle = ppib -> pib_hmte;
if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
GC_err_printf("DosQueryModuleName failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
myexefile = fopen(path, "rb");
if (myexefile == 0) {
GC_err_puts("Couldn't open executable ");
GC_err_puts(path); GC_err_puts("\n");
- ABORT("Failed to open executable\n");
+ ABORT("Failed to open executable");
}
if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
GC_err_puts("Couldn't read MSDOS header from ");
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
index d799eab2..421151fe 100644
--- a/pthread_stop_world.c
+++ b/pthread_stop_world.c
@@ -324,7 +324,7 @@ GC_INNER void GC_push_all_stacks(void)
GC_printf("Stack for thread 0x%x = [%p,%p)\n",
(unsigned)(p -> id), lo, hi);
# endif
- if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
+ if (0 == lo) ABORT("GC_push_all_stacks: sp not set!");
GC_push_all_stack_frames(lo, hi, p -> activation_frame);
# ifdef STACK_GROWS_UP
total_size += lo - hi;
diff --git a/pthread_support.c b/pthread_support.c
index 7ff0c673..6f9fefa0 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -188,7 +188,7 @@ GC_INNER unsigned long GC_lock_holder = NO_THREAD;
namebuf[len] = '\0';
dl_handle = dlopen(namebuf, RTLD_LAZY);
}
- if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");
+ if (NULL == dl_handle) ABORT("Couldn't open libpthread");
# endif
REAL_FUNC(pthread_create) = (GC_pthread_create_t)
dlsym(dl_handle, "pthread_create");
@@ -328,10 +328,10 @@ static void start_mark_threads(void)
int code;
if (pthread_attr_getstacksize(&attr, &old_size) != 0)
- ABORT("pthread_attr_getstacksize failed\n");
+ ABORT("pthread_attr_getstacksize failed");
if (old_size < MIN_STACK_SIZE) {
if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
- ABORT("pthread_attr_setstacksize failed\n");
+ ABORT("pthread_attr_setstacksize failed");
}
}
# endif /* HPUX || GC_DGUX386_THREADS */