From 26876c4acc1a1ab75950597207563c06446e8be7 Mon Sep 17 00:00:00 2001 From: ivmai Date: Thu, 10 Sep 2009 20:13:03 +0000 Subject: [PATCH] 2009-09-10 Ivan Maidanski (ivmai120a.diff, ivmai120b.diff) * Makefile.direct (GC_PTHREADS_PARAMARK, GC_IGNORE_GCJ_INFO, GC_PRINT_VERBOSE_STATS, GC_DONT_EXPAND, GC_INITIAL_HEAP_SIZE, GC_FREE_SPACE_DIVISOR, GC_TIME_LIMIT, GC_FULL_FREQ): Add the comment for. * misc.c (GC_init_inner): Recognize GC_PRINT_VERBOSE_STATS (new macro). * dyn_load.c (GC_wnt): Change definition to TRUE for WinCE; add FIXME and the comment for WinCE. * gcj_mlc.c (GC_init_gcj_malloc): Recognize GC_IGNORE_GCJ_INFO (new macro). * include/gc.h (GC_HAVE_BUILTIN_BACKTRACE): Don't define for VC++ WinCE (since backtrace() is unimplemented). * include/private/gc_priv.h (GC_n_heap_bases): Remove declaration (since static). * os_dep.c (GC_n_heap_bases): Define as STATIC; move the definition to be above GC_is_heap_base(). * include/private/gcconfig.h: Don't define NOSYS for WinCE on ARM (both for MinGW and CeGCC toolchains). * include/private/gcconfig.h: Recognize __CEGCC__ and __MINGW32CE__ (as synonyms for __WIN32_WCE). * include/private/gcconfig.h: If SH4 then don't set config parameters for SH. * include/private/thread_local_alloc.h (GC_key_create): Don't abort on failures, just return -1 in these cases (this also prevents compilation error for targets where ABORT is defined indirectly as an inline assembler sequence). * mark.c (WRAP_MARK_SOME): Also define for WinCE; add FIXME for the GCC-based cross-compiler. * mark.c (ext_ex_regn, mark_ex_handler): Don't define unless WRAP_MARK_SOME is defined; define also for WinCE case; don't check for _WIN64 (since WRAP_MARK_SOME is undefined for it). * mark.c (GC_mark_some): Use __try/__except also for WinCE; update the comment. * misc.c: Include signal.h after gc_pmark.h included; check for MSWINCE instead of _WIN32_WCE. * misc.c (GC_init_inner): Remove duplicate GC_setpagesize() call. * misc.c: Don't include for WinCE targets. * misc.c (GC_write): Define _MAX_PATH if undefined (workaround for CeGCC toolchain). * misc.c (GC_write): Use OutputDebugStringW() instead of _CrtDbgReport() for WinCE targets. * os_dep.c (GC_least_described_address): Define as STATIC. * os_dep.c (GC_register_data_segments): Fix code indentation. * os_dep.c (GC_wince_get_mem): Initialize "result" local variable (to prevent a compiler warning). * os_dep.c (GC_dirty_init): Add comment for WinCE target. * tests/test.c: Don't include winbase.h directly if GCC for WinCE, include assert.h instead. * tests/test.c (tiny_reverse_test): Define and use TINY_REVERSE_UPPER_VALUE macro (4 if VERY_SMALL_CONFIG else 10); useful for WinCE. * win32_threads.c (GC_Thread_Rep): Don't declare "handle" field for WinCE (since thread Id is used as a "real" thread handle). * win32_threads.c (THREAD_HANDLE): New macro. * win32_threads.c (GC_register_my_thread_inner): Don't recognize DONT_IMPORT_GETCURTHREAD anymore; don't record thread handle on WinCE. * Makefile.direct (DONT_IMPORT_GETCURTHREAD): Remove comment for. * win32_threads.c (UNPROTECT, GC_fault_handler_lock): Don't check for MSWINCE. * win32_threads.c (GC_delete_gc_thread, GC_delete_thread): Don't close thread handle on WinCE (since it's a thread Id). * win32_threads.c (GC_suspend): Don't check for MSWINCE in the MPROTECT-related code (for the case if MPROTECT_VDB would be implemented for WinCE). * win32_threads.c (GC_suspend, GC_start_world, GC_push_stack_for): Use THREAD_HANDLE(t) to obtain thread handle. * win32_threads.c (GC_PTHREADS_PARAMARK): New macro recognized; implicitly define GC_PTHREADS_PARAMARK if GC_PTHREADS; include pthread.h; define NUMERIC_THREAD_ID(id) if undefined yet; replace GC_PTHREADS with GC_PTHREADS_PARAMARK where appropriate (for the parallel mark support). * win32_threads.c (start_mark_threads): Use int type for "i" local variable (instead of "unsigned") to prevent a compiler warning. * win32_threads.c (start_mark_threads): Don't check CreateThread() result for -1; call CloseHandle() for the handle created by CreateThread() (on WinCE); don't use errno (since errno.h is missing on some targets like WinCE) when printing warning on a marker thread creation failure. * win32_threads.c (signalObjectAndWait_func): Define for WinCE. * win32_threads.c (GC_wait_marker): Remove unnecessary assertion for non-zero signalObjectAndWait_func (to make the code compilable for WinCE). * win32_threads.c (GC_thr_init): Allow PARALLEL_MARK for WinCE; use GC_sysinfo to get processors count if WinCE; don't check for SignalObjectAndWait() if WinCE; replace GC_PTHREADS with GC_PTHREADS_PARAMARK. * win32_threads.c (GC_thr_init): Recognize GC_MIN_MARKERS new macro (useful for testing parallel marking on WinCE). * win32_threads.c (GC_win32_start, main_thread_start): Define as STATIC. * win32_threads.c: Don't define main_thread_args, main_thread_start(), WinMain() for WinCE if GC_DLL. * win32_threads.c (WINCE_MAIN_STACK_SIZE): Remove useless macro (since the stack size parameter is ignored on WinCE). * win32_threads.c (main_thread_start): Remove forward declaration; place its definition before WinMain() one. * win32_threads.c (WinMain): Abort if GC_CreateThread() or WaitForSingleObject() failed (for the main thread). --- ChangeLog | 103 +++++++++++++++ Makefile.direct | 20 ++- dyn_load.c | 7 +- gcj_mlc.c | 7 +- include/gc.h | 7 +- include/private/gc_priv.h | 1 - include/private/gcconfig.h | 7 +- include/private/thread_local_alloc.h | 5 +- mark.c | 23 +++- misc.c | 51 ++++--- os_dep.c | 19 +-- tests/test.c | 11 +- win32_threads.c | 191 ++++++++++++++++----------- 13 files changed, 326 insertions(+), 126 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3626918c..9f8313e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,107 @@ +2009-09-10 Ivan Maidanski + (ivmai120a.diff, ivmai120b.diff) + + * Makefile.direct (GC_PTHREADS_PARAMARK, GC_IGNORE_GCJ_INFO, + GC_PRINT_VERBOSE_STATS, GC_DONT_EXPAND, GC_INITIAL_HEAP_SIZE, + GC_FREE_SPACE_DIVISOR, GC_TIME_LIMIT, GC_FULL_FREQ): Add the + comment for. + * misc.c (GC_init_inner): Recognize GC_PRINT_VERBOSE_STATS (new + macro). + * dyn_load.c (GC_wnt): Change definition to TRUE for WinCE; add + FIXME and the comment for WinCE. + * gcj_mlc.c (GC_init_gcj_malloc): Recognize GC_IGNORE_GCJ_INFO + (new macro). + * include/gc.h (GC_HAVE_BUILTIN_BACKTRACE): Don't define for VC++ + WinCE (since backtrace() is unimplemented). + * include/private/gc_priv.h (GC_n_heap_bases): Remove declaration + (since static). + * os_dep.c (GC_n_heap_bases): Define as STATIC; move the + definition to be above GC_is_heap_base(). + * include/private/gcconfig.h: Don't define NOSYS for WinCE on ARM + (both for MinGW and CeGCC toolchains). + * include/private/gcconfig.h: Recognize __CEGCC__ and + __MINGW32CE__ (as synonyms for __WIN32_WCE). + * include/private/gcconfig.h: If SH4 then don't set config + parameters for SH. + * include/private/thread_local_alloc.h (GC_key_create): Don't + abort on failures, just return -1 in these cases (this also + prevents compilation error for targets where ABORT is defined + indirectly as an inline assembler sequence). + * mark.c (WRAP_MARK_SOME): Also define for WinCE; add FIXME for + the GCC-based cross-compiler. + * mark.c (ext_ex_regn, mark_ex_handler): Don't define unless + WRAP_MARK_SOME is defined; define also for WinCE case; don't + check for _WIN64 (since WRAP_MARK_SOME is undefined for it). + * mark.c (GC_mark_some): Use __try/__except also for WinCE; update + the comment. + * misc.c: Include signal.h after gc_pmark.h included; check for + MSWINCE instead of _WIN32_WCE. + * misc.c (GC_init_inner): Remove duplicate GC_setpagesize() call. + * misc.c: Don't include for WinCE targets. + * misc.c (GC_write): Define _MAX_PATH if undefined (workaround for + CeGCC toolchain). + * misc.c (GC_write): Use OutputDebugStringW() instead of + _CrtDbgReport() for WinCE targets. + * os_dep.c (GC_least_described_address): Define as STATIC. + * os_dep.c (GC_register_data_segments): Fix code indentation. + * os_dep.c (GC_wince_get_mem): Initialize "result" local variable + (to prevent a compiler warning). + * os_dep.c (GC_dirty_init): Add comment for WinCE target. + * tests/test.c: Don't include winbase.h directly if GCC for WinCE, + include assert.h instead. + * tests/test.c (tiny_reverse_test): Define and use + TINY_REVERSE_UPPER_VALUE macro (4 if VERY_SMALL_CONFIG else 10); + useful for WinCE. + * win32_threads.c (GC_Thread_Rep): Don't declare "handle" field + for WinCE (since thread Id is used as a "real" thread handle). + * win32_threads.c (THREAD_HANDLE): New macro. + * win32_threads.c (GC_register_my_thread_inner): Don't recognize + DONT_IMPORT_GETCURTHREAD anymore; don't record thread handle on + WinCE. + * Makefile.direct (DONT_IMPORT_GETCURTHREAD): Remove comment for. + * win32_threads.c (UNPROTECT, GC_fault_handler_lock): Don't check + for MSWINCE. + * win32_threads.c (GC_delete_gc_thread, GC_delete_thread): Don't + close thread handle on WinCE (since it's a thread Id). + * win32_threads.c (GC_suspend): Don't check for MSWINCE in the + MPROTECT-related code (for the case if MPROTECT_VDB would be + implemented for WinCE). + * win32_threads.c (GC_suspend, GC_start_world, GC_push_stack_for): + Use THREAD_HANDLE(t) to obtain thread handle. + * win32_threads.c (GC_PTHREADS_PARAMARK): New macro recognized; + implicitly define GC_PTHREADS_PARAMARK if GC_PTHREADS; include + pthread.h; define NUMERIC_THREAD_ID(id) if undefined yet; replace + GC_PTHREADS with GC_PTHREADS_PARAMARK where appropriate (for the + parallel mark support). + * win32_threads.c (start_mark_threads): Use int type for "i" local + variable (instead of "unsigned") to prevent a compiler warning. + * win32_threads.c (start_mark_threads): Don't check CreateThread() + result for -1; call CloseHandle() for the handle created by + CreateThread() (on WinCE); don't use errno (since errno.h is + missing on some targets like WinCE) when printing warning on a + marker thread creation failure. + * win32_threads.c (signalObjectAndWait_func): Define for WinCE. + * win32_threads.c (GC_wait_marker): Remove unnecessary assertion + for non-zero signalObjectAndWait_func (to make the code compilable + for WinCE). + * win32_threads.c (GC_thr_init): Allow PARALLEL_MARK for WinCE; + use GC_sysinfo to get processors count if WinCE; don't check for + SignalObjectAndWait() if WinCE; replace GC_PTHREADS with + GC_PTHREADS_PARAMARK. + * win32_threads.c (GC_thr_init): Recognize GC_MIN_MARKERS new + macro (useful for testing parallel marking on WinCE). + * win32_threads.c (GC_win32_start, main_thread_start): Define as + STATIC. + * win32_threads.c: Don't define main_thread_args, + main_thread_start(), WinMain() for WinCE if GC_DLL. + * win32_threads.c (WINCE_MAIN_STACK_SIZE): Remove useless macro + (since the stack size parameter is ignored on WinCE). + * win32_threads.c (main_thread_start): Remove forward declaration; + place its definition before WinMain() one. + * win32_threads.c (WinMain): Abort if GC_CreateThread() or + WaitForSingleObject() failed (for the main thread). + 2009-09-10 Ivan Maidanski (diff118_cvs - superseding diff53) diff --git a/Makefile.direct b/Makefile.direct index a4e62135..ecdb065f 100644 --- a/Makefile.direct +++ b/Makefile.direct @@ -95,6 +95,8 @@ HOSTCFLAGS=$(CFLAGS) # threads. # -DPTW32_STATIC_LIB causes the static version of the Mingw pthreads library # to be used. Requires -DGC_WIN32_PTHREADS. +# -DGC_PTHREADS_PARAMARK causes pthread-based parallel mark implementation +# to be used even if GC_WIN32_PTHREADS is undefined. (Useful for WinCE.) # # -DALL_INTERIOR_POINTERS allows all pointers to the interior # of objects to be recognized. (See gc_priv.h for consequences.) @@ -336,9 +338,21 @@ HOSTCFLAGS=$(CFLAGS) # to force MPROTECT_VDB strategy instead of the default GWW_VDB one). # -DGC_NO_DLLMAIN (Win32+DLL only) Exclude DllMain-based thread registration # support. -# -DDONT_IMPORT_GETCURTHREAD (Win32 only) Use MS hard-coded thread-self -# pseudohandle value (-2) instead of linking (or binding) to a real -# GetCurrentThread() func; mostly useful on WinCE unless "UNDER_CE" mode. +# -DGC_IGNORE_GCJ_INFO Disable GCJ-style type information (useful for +# debugging on WinCE). +# -DGC_PRINT_VERBOSE_STATS Permanently turn on verbose logging (useful for +# debugging and profiling on WinCE). +# -DGC_DONT_EXPAND Dont expand the heap unless explicitly requested or +# forced to. +# -DGC_INITIAL_HEAP_SIZE= Set the desired default initial heap size +# in bytes. +# -DGC_FREE_SPACE_DIVISOR= Set alternate default GC_free_space_divisor +# value. +# -DGC_TIME_LIMIT= Set alternate default GC_time_limit value +# (setting this to GC_TIME_UNLIMITED will essentially disable incremental +# collection while leaving generational collection enabled). +# -DGC_FULL_FREQ= Set alternate default number of partial collections +# between full collections (matters only if incremental collection is on). # CXXFLAGS= $(CFLAGS) diff --git a/dyn_load.c b/dyn_load.c index 920d17de..fba9ecb2 100644 --- a/dyn_load.c +++ b/dyn_load.c @@ -860,7 +860,12 @@ void GC_register_dynamic_libraries(void) # endif /* DEBUG_VIRTUALQUERY */ # ifdef MSWINCE -# define GC_wnt FALSE + /* FIXME: Should we really need to scan MEM_PRIVATE sections? */ + /* For now, we don't add MEM_PRIVATE sections to the data roots for */ + /* WinCE because otherwise SEGV fault sometimes happens to occur in */ + /* GC_mark_from() (and, even if we use WRAP_MARK_SOME, WinCE prints */ + /* a "Data Abort" message to the debugging console). */ +# define GC_wnt TRUE # else extern GC_bool GC_wnt; /* Is Windows NT derivative. */ /* Defined and set in os_dep.c. */ diff --git a/gcj_mlc.c b/gcj_mlc.c index 5d772ff7..b4b0f522 100644 --- a/gcj_mlc.c +++ b/gcj_mlc.c @@ -64,7 +64,12 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index, return; } GC_gcj_malloc_initialized = TRUE; - ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO")); +# ifdef GC_IGNORE_GCJ_INFO + /* This is useful for debugging on platforms with missing getenv(). */ + ignore_gcj_info = 1; +# else + ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO")); +# endif if (GC_print_stats && ignore_gcj_info) { GC_log_printf("Gcj-style type information is disabled!\n"); } diff --git a/include/gc.h b/include/gc.h index ca1b5997..6963d1f6 100644 --- a/include/gc.h +++ b/include/gc.h @@ -591,10 +591,9 @@ GC_API void * GC_CALL GC_malloc_atomic_ignore_off_page(size_t /* lb */) #endif #if defined(_MSC_VER) && _MSC_VER >= 1200 /* version 12.0+ (MSVC 6.0+) */ \ - && !defined(_AMD64_) -# ifndef GC_HAVE_NO_BUILTIN_BACKTRACE -# define GC_HAVE_BUILTIN_BACKTRACE -# endif + && !defined(_AMD64_) && !defined(GC_HAVE_NO_BUILTIN_BACKTRACE) \ + && !defined(_WIN32_WCE) && !defined(GC_HAVE_BUILTIN_BACKTRACE) +# define GC_HAVE_BUILTIN_BACKTRACE #endif #if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS) diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 43e971d5..39eb8e5f 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -1218,7 +1218,6 @@ extern word GC_page_size; # if defined(MSWIN32) || defined(MSWINCE) struct _SYSTEM_INFO; extern struct _SYSTEM_INFO GC_sysinfo; - extern word GC_n_heap_bases; /* See GC_heap_bases. */ # endif extern word GC_total_stack_black_listed; diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index 6b5cedc7..e5b18e15 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -69,7 +69,8 @@ /* Determine the machine type: */ # if defined(__arm__) || defined(__thumb__) # define ARM32 -# if !defined(LINUX) && !defined(NETBSD) && !defined(DARWIN) +# if !defined(LINUX) && !defined(NETBSD) && !defined(DARWIN) \ + && !defined(_WIN32) && !defined(__CEGCC__) # define NOSYS # define mach_type_known # endif @@ -366,7 +367,7 @@ /* DGUX defined */ # define mach_type_known # endif -# if defined(_WIN32_WCE) +# if defined(_WIN32_WCE) || defined(__CEGCC__) || defined(__MINGW32CE__) /* SH3, SH4, MIPS already defined for corresponding architectures */ # if defined(SH3) || defined(SH4) # define SH @@ -1803,7 +1804,7 @@ # define DATAEND (ptr_t)(_end) # endif -# ifdef SH +# if defined(SH) && !defined(SH4) # define MACH_TYPE "SH" # define ALIGNMENT 4 # ifdef MSWINCE diff --git a/include/private/thread_local_alloc.h b/include/private/thread_local_alloc.h index 9bfbcb52..eb30487b 100644 --- a/include/private/thread_local_alloc.h +++ b/include/private/thread_local_alloc.h @@ -113,10 +113,7 @@ typedef struct thread_local_freelists { # define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF # endif # define GC_key_create(key, d) \ - ((d) != 0? (ABORT("Destructor unsupported by TlsAlloc"),0) \ - : ((*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES? \ - (ABORT("Out of tls"), 0): \ - 0)) + ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0) # define GC_remove_specific(key) /* No need for cleanup on thread exit. */ /* Need TlsFree on process exit/detach ? */ typedef DWORD GC_key_t; diff --git a/mark.c b/mark.c index 4549dade..36b91346 100644 --- a/mark.c +++ b/mark.c @@ -283,11 +283,16 @@ void GC_initiate_gc(void) static void alloc_mark_stack(size_t); -# if defined(MSWIN32) && (!defined(__GNUC__) || !defined(_WIN64)) \ +# if (defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__) \ + || defined(MSWIN32) && defined(I386) /* for Win98 */ \ || defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS) /* Under rare conditions, we may end up marking from nonexistent memory. */ /* Hence we need to be prepared to recover by running GC_mark_some */ /* with a suitable handler in place. */ + /* FIXME: Should we really need it for WinCE? If yes then */ + /* WRAP_MARK_SOME should be also defined for CeGCC which requires */ + /* CPU/OS-specific code in mark_ex_handler() and GC_mark_some() */ + /* (for manual stack unwinding and exception handler installation). */ # define WRAP_MARK_SOME # endif @@ -430,8 +435,9 @@ static void alloc_mark_stack(size_t); } } +#ifdef WRAP_MARK_SOME -#if defined(MSWIN32) && defined(__GNUC__) && !defined(_WIN64) +# if (defined(MSWIN32) || defined(MSWINCE)) && defined(__GNUC__) typedef struct { EXCEPTION_REGISTRATION ex_reg; @@ -474,12 +480,11 @@ static void alloc_mark_stack(size_t); /* unexpected thread start? */ #endif -# ifdef WRAP_MARK_SOME GC_bool GC_mark_some(ptr_t cold_gc_frame) { GC_bool ret_val; -# ifdef MSWIN32 +# if defined(MSWIN32) || defined(MSWINCE) # ifndef __GNUC__ /* Windows 98 appears to asynchronously create and remove */ /* writable memory mappings, for reasons we haven't yet */ @@ -488,8 +493,11 @@ static void alloc_mark_stack(size_t); /* address range that disappeared since we started the */ /* collection. Thus we have to recover from faults here. */ /* This code does not appear to be necessary for Windows */ - /* 95/NT/2000. Note that this code should never generate */ + /* 95/NT/2000+. Note that this code should never generate */ /* an incremental GC write fault. */ + /* This code seems to be necessary for WinCE (at least in */ + /* the case we'd decide to add MEM_PRIVATE sections to */ + /* data roots in GC_register_dynamic_libraries()). */ /* It's conceivable that this is the same issue with */ /* terminating threads that we see with Linux and */ /* USE_PROC_FOR_LIBRARIES. */ @@ -540,9 +548,10 @@ static void alloc_mark_stack(size_t); /* thread that is in the process of exiting, and disappears */ /* while we are marking it. This seems extremely difficult to */ /* avoid otherwise. */ - if (GC_incremental) - WARN("Incremental GC incompatible with /proc roots\n", 0); + if (GC_incremental) { + WARN("Incremental GC incompatible with /proc roots\n", 0); /* I'm not sure if this could still work ... */ + } GC_setup_temporary_fault_handler(); if(SETJMP(GC_jmp_buf) != 0) goto handle_ex; ret_val = GC_mark_some_inner(cold_gc_frame); diff --git a/misc.c b/misc.c index e5e06c28..a0eba18f 100644 --- a/misc.c +++ b/misc.c @@ -18,13 +18,14 @@ #include #include #include -#ifndef _WIN32_WCE -#include -#endif #define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */ #include "private/gc_pmark.h" +#ifndef MSWINCE +# include +#endif + #ifdef GC_SOLARIS_THREADS # include #endif @@ -540,17 +541,22 @@ void GC_init_inner(void) # endif /* !MSWINCE */ /* else */ InitializeCriticalSection (&GC_allocate_ml); } -#endif /* MSWIN32 */ +# endif /* GC_WIN32_THREADS */ # if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS) InitializeCriticalSection(&GC_write_cs); # endif # if (!defined(SMALL_CONFIG)) - if (0 != GETENV("GC_PRINT_STATS")) { - GC_print_stats = 1; - } - if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) { - GC_print_stats = VERBOSE; - } +# ifdef GC_PRINT_VERBOSE_STATS + /* This is useful for debugging and profiling on platforms with */ + /* missing getenv() (like WinCE). */ + GC_print_stats = VERBOSE; +# else + if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) { + GC_print_stats = VERBOSE; + } else if (0 != GETENV("GC_PRINT_STATS")) { + GC_print_stats = 1; + } +# endif # if defined(UNIX_LIKE) || defined(CYGWIN32) { char * file_name = GETENV("GC_LOG_FILE"); @@ -732,8 +738,6 @@ void GC_init_inner(void) GC_STATIC_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(); @@ -887,8 +891,9 @@ out: #if defined(MSWIN32) || defined(MSWINCE) -# if defined(_MSC_VER) && defined(_DEBUG) -# include + +# if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE) +# include # endif STATIC HANDLE GC_stdout = 0; @@ -910,6 +915,10 @@ out: # endif #else # define IF_NEED_TO_LOCK(x) +#endif + +#ifndef _MAX_PATH +# define _MAX_PATH MAX_PATH #endif STATIC HANDLE GC_CreateLogFile(void) @@ -961,7 +970,19 @@ out: if (!tmp) DebugBreak(); # if defined(_MSC_VER) && defined(_DEBUG) - _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf); +# ifdef MSWINCE + /* There is no CrtDbgReport() in WinCE */ + { + WCHAR wbuf[1024]; + /* Always use Unicode variant of OutputDebugString() */ + wbuf[MultiByteToWideChar(CP_ACP, 0 /* dwFlags */, + buf, len, wbuf, + sizeof(wbuf) / sizeof(wbuf[0]) - 1)] = 0; + OutputDebugStringW(wbuf); + } +# else + _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf); +# endif # endif IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs)); return tmp ? (int)written : -1; diff --git a/os_dep.c b/os_dep.c index 26135e9d..3cc6d497 100644 --- a/os_dep.c +++ b/os_dep.c @@ -1384,7 +1384,7 @@ void GC_register_data_segments(void) /* Return the smallest address a such that VirtualQuery */ /* returns correct results for all addresses between a and start. */ /* Assumes VirtualQuery returns correct information for start. */ - ptr_t GC_least_described_address(ptr_t start) + STATIC ptr_t GC_least_described_address(ptr_t start) { MEMORY_BASIC_INFORMATION buf; size_t result; @@ -1477,6 +1477,8 @@ void GC_register_data_segments(void) } # endif /* REDIRECT_MALLOC */ + STATIC word GC_n_heap_bases = 0; /* See GC_heap_bases. */ + /* Is p the start of either the malloc heap, or of one of our */ /* heap sections? */ GC_bool GC_is_heap_base (ptr_t p) @@ -1531,10 +1533,10 @@ void GC_register_data_segments(void) void GC_register_data_segments(void) { -# ifdef MSWIN32 +# ifdef MSWIN32 static char dummy; GC_register_root_section((ptr_t)(&dummy)); -# endif +# endif } # else /* !OS2 && !Windows */ @@ -1859,8 +1861,6 @@ SYSTEM_INFO GC_sysinfo; # define GLOBAL_ALLOC_TEST GC_no_win32_dlls # endif -word GC_n_heap_bases = 0; - #ifdef GC_USE_MEM_TOP_DOWN STATIC DWORD GC_mem_top_down = MEM_TOP_DOWN; /* Use GC_USE_MEM_TOP_DOWN for better 64-bit */ @@ -1929,11 +1929,9 @@ GC_API void GC_CALL GC_win32_free_heap(void) # ifdef MSWINCE -word GC_n_heap_bases = 0; - ptr_t GC_wince_get_mem(word bytes) { - ptr_t result; + ptr_t result = 0; /* initialized to prevent warning. */ word i; /* Round up allocation size to multiple of page size */ @@ -2637,7 +2635,7 @@ STATIC GC_bool GC_old_segv_handler_used_si; set_pht_entry_from_index(db, index); AO_CLEAR(&GC_fault_handler_lock); } -#else /* !AO_have_test_and_set_acquire */ +#else /* !AO_HAVE_test_and_set_acquire */ # error No test_and_set operation: Introduces a race. /* THIS WOULD BE INCORRECT! */ /* The dirty bit vector may be temporarily wrong, */ @@ -2941,6 +2939,9 @@ void GC_dirty_init(void) } else { GC_old_segv_handler = SIG_DFL; } +# elif defined(MSWINCE) + /* MPROTECT_VDB is unsupported for WinCE at present. */ + /* FIXME: implement it (if possible). */ # endif } #endif /* !DARWIN */ diff --git a/tests/test.c b/tests/test.c index 6650a72d..b32dac1f 100644 --- a/tests/test.c +++ b/tests/test.c @@ -39,7 +39,7 @@ # include # endif # include -# ifdef _WIN32_WCE +# if defined(_WIN32_WCE) && !defined(__GNUC__) # include /* # define assert ASSERT */ # else @@ -444,6 +444,12 @@ void check_marks_int_list(sexpr x) */ #ifdef THREADS +# ifdef VERY_SMALL_CONFIG +# define TINY_REVERSE_UPPER_VALUE 4 +# else +# define TINY_REVERSE_UPPER_VALUE 10 +# endif + # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) DWORD __stdcall tiny_reverse_test(void * arg) # else @@ -452,7 +458,8 @@ void check_marks_int_list(sexpr x) { int i; for (i = 0; i < 5; ++i) { - check_ints(reverse(reverse(ints(1,10))), 1, 10); + check_ints(reverse(reverse(ints(1, TINY_REVERSE_UPPER_VALUE))), + 1, TINY_REVERSE_UPPER_VALUE); } return 0; } diff --git a/win32_threads.c b/win32_threads.c index 9e9a0d78..00b5d001 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -36,7 +36,7 @@ #endif #ifdef GC_PTHREADS -# include +# include /* for EAGAIN */ /* Cygwin-specific forward decls */ # undef pthread_create @@ -195,7 +195,19 @@ struct GC_Thread_Rep { # define in_use table_management.tm_in_use # define next table_management.tm_next DWORD id; - HANDLE handle; + +# ifdef MSWINCE + /* According to MSDN specs for WinCE targets: */ + /* - DuplicateHandle() is not applicable to thread handles; and */ + /* - the value returned by GetCurrentThreadId() could be used as */ + /* a "real" thread handle (for SuspendThread(), ResumeThread() and */ + /* GetThreadContext()). */ +# define THREAD_HANDLE(t) (HANDLE)(t)->id +# else + HANDLE handle; +# define THREAD_HANDLE(t) (t)->handle +# endif + ptr_t stack_base; /* The cold end of the stack. */ /* 0 ==> entry not valid. */ /* !in_use ==> stack_base == 0 */ @@ -415,23 +427,17 @@ static GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb, /* me can be NULL -> segfault */ me -> pthread_id = pthread_self(); # endif - -# if defined(DONT_IMPORT_GETCURTHREAD) && !defined(UNDER_CE) - /* This simplifies linking for some WinAPI systems (like WinCE). */ -# undef GetCurrentThread -# define GetCurrentThread() (HANDLE)-2L /* "thread_self" pseudohandle */ -# endif - - if (!DuplicateHandle(GetCurrentProcess(), - GetCurrentThread(), +# ifndef MSWINCE + /* GetCurrentThread() returns a pseudohandle (a const value). */ + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), (HANDLE*)&(me -> handle), - 0, - 0, + 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */, DUPLICATE_SAME_ACCESS)) { GC_err_printf("Last error code: %d\n", (int)GetLastError()); ABORT("DuplicateHandle failed"); - } + } +# endif me -> last_stack_min = ADDR_LIMIT; me -> stack_base = sb -> mem_base; # ifdef IA64 @@ -550,7 +556,7 @@ unsigned *GC_check_finalizer_nested(void) /* Used to prevent write faults when the world is (partially) stopped, */ /* since it may have been stopped with a system lock held, and that */ /* lock may be required for fault handling. */ -# if defined(MPROTECT_VDB) && !defined(MSWINCE) +# if defined(MPROTECT_VDB) # define UNPROTECT(t) \ if (GC_dirty_maintained && !GC_win32_dll_threads && \ t != &first_thread) { \ @@ -558,7 +564,7 @@ unsigned *GC_check_finalizer_nested(void) GC_remove_protection(HBLKPTR(t), 1, FALSE); \ } # else -# define UNPROTECT(p) +# define UNPROTECT(t) # endif /* If a thread has been joined, but we have not yet */ @@ -571,7 +577,9 @@ unsigned *GC_check_finalizer_nested(void) /* thread being deleted. */ STATIC void GC_delete_gc_thread(GC_vthread gc_id) { - CloseHandle(gc_id->handle); +# ifndef MSWINCE + CloseHandle(gc_id->handle); +# endif #ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { /* This is intended to be lock-free. */ @@ -637,7 +645,9 @@ STATIC void GC_delete_thread(DWORD id) prev = p; p = p -> next; } - CloseHandle(p->handle); +# ifndef MSWINCE + CloseHandle(p->handle); +# endif if (prev == 0) { GC_threads[hv] = p -> next; } else { @@ -796,7 +806,7 @@ void GC_push_thread_structures(void) # endif } -#if defined(MPROTECT_VDB) && !defined(MSWINCE) +#if defined(MPROTECT_VDB) # include "atomic_ops.h" extern volatile AO_TS_t GC_fault_handler_lock; /* from os_dep.c */ #endif @@ -804,19 +814,16 @@ void GC_push_thread_structures(void) /* Suspend the given thread, if it's still active. */ STATIC void GC_suspend(GC_thread t) { -# ifdef MSWINCE - /* SuspendThread will fail if thread is running kernel code */ - while (SuspendThread(t -> handle) == (DWORD)-1) - Sleep(10); -# else - /* Apparently the Windows 95 GetOpenFileName call creates */ +# ifndef MSWINCE + /* Apparently the Windows 95 GetOpenFileName call creates */ /* a thread that does not properly get cleaned up, and */ /* SuspendThread on its descriptor may provoke a crash. */ /* This reduces the probability of that event, though it still */ /* appears there's a race here. */ DWORD exitCode; - - UNPROTECT(t); +# endif + UNPROTECT(t); +# ifndef MSWINCE if (GetExitCodeThread(t -> handle, &exitCode) && exitCode != STILL_ACTIVE) { # ifdef GC_PTHREADS @@ -829,20 +836,26 @@ STATIC void GC_suspend(GC_thread t) # endif return; } -# if defined(MPROTECT_VDB) && !defined(MSWINCE) - /* Acquire the spin lock we use to update dirty bits. */ - /* Threads shouldn't get stopped holding it. But we may */ - /* acquire and release it in the UNPROTECT call. */ - while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {} -# endif +# endif +# if defined(MPROTECT_VDB) + /* Acquire the spin lock we use to update dirty bits. */ + /* Threads shouldn't get stopped holding it. But we may */ + /* acquire and release it in the UNPROTECT call. */ + while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {} +# endif +# ifdef MSWINCE + /* SuspendThread() will fail if thread is running kernel code. */ + while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) + Sleep(10); /* in millis */ +# else if (SuspendThread(t -> handle) == (DWORD)-1) ABORT("SuspendThread failed"); +# endif /* !MSWINCE */ + t -> suspended = TRUE; +# if defined(MPROTECT_VDB) + AO_CLEAR(&GC_fault_handler_lock); # endif - t -> suspended = TRUE; -# if defined(MPROTECT_VDB) && !defined(MSWINCE) - AO_CLEAR(&GC_fault_handler_lock); -# endif } /* Defined in misc.c */ @@ -924,7 +937,7 @@ void GC_start_world(void) GC_thread t = (GC_thread)(dll_thread_table + i); if (t -> stack_base != 0 && t -> suspended && t -> id != thread_id) { - if (ResumeThread(t -> handle) == (DWORD)-1) + if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1) ABORT("ResumeThread failed"); t -> suspended = FALSE; } @@ -937,7 +950,7 @@ void GC_start_world(void) for (t = GC_threads[i]; t != 0; t = t -> next) { if (t -> stack_base != 0 && t -> suspended && t -> id != thread_id) { - if (ResumeThread(t -> handle) == (DWORD)-1) + if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1) ABORT("ResumeThread failed"); UNPROTECT(t); t -> suspended = FALSE; @@ -1009,7 +1022,7 @@ STATIC void GC_push_stack_for(GC_thread thread) } else { CONTEXT context; context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; - if (!GetThreadContext(thread -> handle, &context)) + if (!GetThreadContext(THREAD_HANDLE(thread), &context)) ABORT("GetThreadContext failed"); /* Push all registers that might point into the heap. Frame */ @@ -1283,8 +1296,13 @@ void GC_get_next_stack(char *start, char *limit, #ifdef PARALLEL_MARK +#if defined(GC_PTHREADS) && !defined(GC_PTHREADS_PARAMARK) + /* Use pthread-based parallel mark implementation. */ +# define GC_PTHREADS_PARAMARK +#endif + /* GC_mark_thread() is the same as in pthread_support.c */ -#ifdef GC_PTHREADS +#ifdef GC_PTHREADS_PARAMARK STATIC void * GC_mark_thread(void * id) #else # ifdef MSWINCE @@ -1323,7 +1341,12 @@ void GC_get_next_stack(char *start, char *limit, /* GC_mark_threads[] is unused here unlike that in pthread_support.c */ -#ifdef GC_PTHREADS +#ifdef GC_PTHREADS_PARAMARK +# include + +# ifndef NUMERIC_THREAD_ID +# define NUMERIC_THREAD_ID(id) (unsigned long)(id.p) +# endif /* start_mark_threads() is the same as in pthread_support.c except for: */ /* - GC_markers value is adjusted already; */ @@ -1332,7 +1355,7 @@ void GC_get_next_stack(char *start, char *limit, STATIC void start_mark_threads(void) { - unsigned i; + int i; pthread_attr_t attr; pthread_t new_thread; @@ -1345,8 +1368,7 @@ STATIC void start_mark_threads(void) marker_last_stack_min[i] = ADDR_LIMIT; if (0 != pthread_create(&new_thread, &attr, GC_mark_thread, (void *)(word)i)) { - WARN("Marker thread creation failed, errno = %ld.\n", - /* (word) */ errno); + WARN("Marker thread creation failed.\n", 0); } } pthread_attr_destroy(&attr); @@ -1450,7 +1472,7 @@ void GC_notify_all_marker(void) } } -#else /* ! GC_PTHREADS */ +#else /* ! GC_PTHREADS_PARAMARK */ # ifndef MARK_THREAD_STACK_SIZE # define MARK_THREAD_STACK_SIZE 0 /* default value */ @@ -1474,18 +1496,22 @@ STATIC void start_mark_threads(void) handle = CreateThread(NULL /* lpsa */, MARK_THREAD_STACK_SIZE, GC_mark_thread, (LPVOID)(word)i, 0 /* fdwCreate */, &thread_id); - if (!handle || handle == (HANDLE)-1L) + if (handle == NULL) WARN("Marker thread creation failed\n", 0); + else { + /* It's safe to detach the thread. */ + CloseHandle(handle); + } # else handle = _beginthreadex(NULL /* security_attr */, MARK_THREAD_STACK_SIZE, GC_mark_thread, (void *)(word)i, 0 /* flags */, &thread_id); if (!handle || handle == (GC_uintptr_t)-1L) WARN("Marker thread creation failed\n", 0); + else { /* We may detach the thread (if handle is of HANDLE type) */ + /* CloseHandle((HANDLE)handle); */ + } # endif - else { /* We may detach the thread (if handle is of HANDLE type) */ - /* CloseHandle((HANDLE)handle); */ - } } } @@ -1582,9 +1608,16 @@ void GC_notify_all_builder(void) STATIC HANDLE mark_cv = (HANDLE)0; /* Event with manual reset */ -typedef DWORD (WINAPI * SignalObjectAndWait_type)( +#ifdef MSWINCE + /* SignalObjectAndWait() is missing in WinCE (for now), so you should */ + /* supply its emulation (externally) to use this code. */ + WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE, HANDLE, DWORD, BOOL); +# define signalObjectAndWait_func SignalObjectAndWait +#else + typedef DWORD (WINAPI * SignalObjectAndWait_type)( HANDLE, HANDLE, DWORD, BOOL); -STATIC SignalObjectAndWait_type signalObjectAndWait_func = 0; + STATIC SignalObjectAndWait_type signalObjectAndWait_func = 0; +#endif void GC_wait_marker(void) { @@ -1592,7 +1625,6 @@ void GC_wait_marker(void) /* from a while(check_cond) loop. */ AO_t waitcnt; GC_ASSERT(mark_cv != 0); - GC_ASSERT(signalObjectAndWait_func != 0); /* We inline GC_release_mark_lock() to have atomic */ /* unlock-and-wait action here. */ @@ -1608,7 +1640,7 @@ void GC_wait_marker(void) } /* The state of mark_cv is non-signaled here. */ - if ((*signalObjectAndWait_func)(mark_mutex_event /* hObjectToSignal */, + if (signalObjectAndWait_func(mark_mutex_event /* hObjectToSignal */, mark_cv /* hObjectToWaitOn */, INFINITE /* timeout */, FALSE /* isAlertable */) == WAIT_FAILED) @@ -1639,7 +1671,7 @@ void GC_notify_all_marker(void) /* Defined in os_dep.c */ extern GC_bool GC_wnt; -#endif /* ! GC_PTHREADS */ +#endif /* ! GC_PTHREADS_PARAMARK */ #endif /* PARALLEL_MARK */ @@ -1688,7 +1720,7 @@ STATIC void * GC_CALLBACK GC_win32_start_inner(struct GC_stack_base *sb, return ret; } -DWORD WINAPI GC_win32_start(LPVOID arg) +STATIC DWORD WINAPI GC_win32_start(LPVOID arg) { return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner, arg); } @@ -1794,7 +1826,7 @@ GC_API void GC_CALL GC_endthreadex(unsigned retval) #endif /* !GC_PTHREADS */ -#ifdef MSWINCE +#if defined(MSWINCE) && !defined(GC_DLL) typedef struct { HINSTANCE hInstance; @@ -1803,11 +1835,12 @@ typedef struct { int nShowCmd; } main_thread_args; -DWORD WINAPI main_thread_start(LPVOID arg); - -# ifndef WINCE_MAIN_STACK_SIZE -# define WINCE_MAIN_STACK_SIZE 0 /* default value */ -# endif +STATIC DWORD WINAPI main_thread_start(LPVOID arg) +{ + main_thread_args * args = (main_thread_args *) arg; + return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance, + args->lpCmdLine, args->nShowCmd); +} int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, GC_WINMAIN_WINCE_LPTSTR lpCmdLine, int nShowCmd) @@ -1824,15 +1857,18 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, GC_init(); /* start the main thread */ - thread_h = GC_CreateThread(NULL /* lpsa */, WINCE_MAIN_STACK_SIZE, + thread_h = GC_CreateThread(NULL /* lpsa */, 0 /* dwStackSize (ignored) */, main_thread_start, &args, 0 /* fdwCreate */, &thread_id); if (thread_h != NULL) { - WaitForSingleObject (thread_h, INFINITE); + if (WaitForSingleObject (thread_h, INFINITE) == WAIT_FAILED) + ABORT("WaitForSingleObject(main_thread) failed"); GetExitCodeThread (thread_h, &exit_code); CloseHandle (thread_h); + } else { + ABORT("GC_CreateThread(main_thread) failed"); } GC_deinit(); @@ -1841,14 +1877,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, return (int) exit_code; } -DWORD WINAPI main_thread_start(LPVOID arg) -{ - main_thread_args * args = (main_thread_args *) arg; - - return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance, - args->lpCmdLine, args->nShowCmd); -} - #endif /* MSWINCE */ /* Called by GC_init() - we hold the allocation lock. */ @@ -1870,7 +1898,7 @@ void GC_thr_init(void) { GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); -# if defined(PARALLEL_MARK) && !defined(MSWINCE) +# if defined(PARALLEL_MARK) /* Set GC_markers. */ { char * markers_string = GETENV("GC_MARKERS"); @@ -1881,6 +1909,11 @@ void GC_thr_init(void) { GC_markers = MAX_MARKERS; } } else { +# ifdef MSWINCE + /* There is no GetProcessAffinityMask() in WinCE. */ + /* GC_sysinfo is already initialized. */ + GC_markers = GC_sysinfo.dwNumberOfProcessors; +# else # ifdef _WIN64 DWORD_PTR procMask = 0; DWORD_PTR sysMask; @@ -1897,6 +1930,12 @@ void GC_thr_init(void) { } while ((procMask &= procMask - 1) != 0); } GC_markers = ncpu; +# endif +# ifdef GC_MIN_MARKERS + /* This is primarily for testing on systems without getenv(). */ + if (GC_markers < GC_MIN_MARKERS) + GC_markers = GC_MIN_MARKERS; +# endif if (GC_markers >= MAX_MARKERS) GC_markers = MAX_MARKERS; /* silently limit GC_markers value */ } @@ -1904,12 +1943,12 @@ void GC_thr_init(void) { /* Set GC_parallel. */ { -# ifndef GC_PTHREADS +# if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) HMODULE hK32; /* SignalObjectAndWait() API call works only under NT. */ # endif if (GC_markers <= 1 || GC_win32_dll_threads -# ifndef GC_PTHREADS +# if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) || GC_wnt == FALSE || (hK32 = GetModuleHandle(TEXT("kernel32.dll"))) == (HMODULE)0 || (signalObjectAndWait_func = (SignalObjectAndWait_type) @@ -1920,7 +1959,7 @@ void GC_thr_init(void) { GC_parallel = FALSE; GC_markers = 1; } else { -# ifndef GC_PTHREADS +# ifndef GC_PTHREADS_PARAMARK /* Initialize Win32 event objects for parallel marking. */ mark_mutex_event = CreateEvent(NULL /* attrs */, FALSE /* isManualReset */, -- 2.40.0