diff options
author | ivmai <ivmai> | 2009-12-07 17:12:40 +0000 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 21:06:52 +0400 |
commit | 176d5bda1e4416a306005d5ee66a902e9db6af6d (patch) | |
tree | 52e7c56e61bb91f41a8005e16bc61eccca74cb93 | |
parent | a745f0f3f342887988aa9d05c29b2478f0e30101 (diff) | |
download | bdwgc-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-- | ChangeLog | 26 | ||||
-rw-r--r-- | doc/README.macros | 9 | ||||
-rw-r--r-- | include/private/gc_priv.h | 29 | ||||
-rw-r--r-- | mark_rts.c | 2 | ||||
-rw-r--r-- | misc.c | 121 | ||||
-rw-r--r-- | os_dep.c | 8 | ||||
-rw-r--r-- | pthread_stop_world.c | 2 | ||||
-rw-r--r-- | pthread_support.c | 6 |
8 files changed, 171 insertions, 32 deletions
@@ -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) @@ -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; @@ -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 @@ -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 */ |