]> granicus.if.org Git - gc/commitdiff
2009-09-10 Ivan Maidanski <ivmai@mail.ru>
authorivmai <ivmai>
Thu, 10 Sep 2009 20:13:03 +0000 (20:13 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 17:06:46 +0000 (21:06 +0400)
(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 <crtdbg.h> 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).

13 files changed:
ChangeLog
Makefile.direct
dyn_load.c
gcj_mlc.c
include/gc.h
include/private/gc_priv.h
include/private/gcconfig.h
include/private/thread_local_alloc.h
mark.c
misc.c
os_dep.c
tests/test.c
win32_threads.c

index 3626918c415796b5a3e43bc28920ced0bde52cfa..9f8313e787dd8c1ff16b7cd0f5b7d15016ee8b40 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,107 @@
 
+2009-09-10  Ivan Maidanski <ivmai@mail.ru>
+       (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 <crtdbg.h> 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 <ivmai@mail.ru>
        (diff118_cvs - superseding diff53)
 
index a4e621357325328815fcbf9d95ae48bfc4480582..ecdb065fb1e4c749cf4d7bf7a3b22eac1d1ce269 100644 (file)
@@ -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=<value> Set the desired default initial heap size
+#   in bytes.
+# -DGC_FREE_SPACE_DIVISOR=<value> Set alternate default GC_free_space_divisor
+#   value.
+# -DGC_TIME_LIMIT=<milliseconds> 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=<value> Set alternate default number of partial collections
+#   between full collections (matters only if incremental collection is on).
 #
 
 CXXFLAGS= $(CFLAGS) 
index 920d17deb280ba1b73c5a65d6ed4117ab32870ca..fba9ecb28a7b374fd5346c3a80393f49e87f87a6 100644 (file)
@@ -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. */
index 5d772ff7470fc96698e3fbe3e015438ee6883664..b4b0f522a5988fb3edb6943ee3af1c5051c7c745 100644 (file)
--- 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");
     }
index ca1b5997f0363cacf36976f6ec90ce1e3b348c08..6963d1f64f26e976d92e4702ebe493070b65f79a 100644 (file)
@@ -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)
index 43e971d56755b7c20e68e14708b7cada7cdcdd3c..39eb8e5fed2555d7dea79952a933fbdb046221b8 100644 (file)
@@ -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;
index 6b5cedc7931946d6b5393e79b3c794c15b53fcbd..e5b18e15c6f4923c3f4766bc5faca15572da4ad9 100644 (file)
@@ -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
     /* 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
 #   define DATAEND (ptr_t)(_end)
 # endif
 
-# ifdef SH
+# if defined(SH) && !defined(SH4)
 #   define MACH_TYPE "SH"
 #   define ALIGNMENT 4
 #   ifdef MSWINCE
index 9bfbcb521d6e03131f3d8cb0984ae0420719299a..eb30487b1cee9d9460f01fd6b1165ed3adc1581b 100644 (file)
@@ -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 4549dade4897e1ea88f0d9d08a29fb6e8157113d..36b91346eb382e433d9e5cd413b0d40765bbe0f9 100644 (file)
--- 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 e5e06c28077d3add947201c256bfa87bb605ed2a..a0eba18f0063b8c62b782e4db080e284cfb482a0 100644 (file)
--- a/misc.c
+++ b/misc.c
 #include <stdio.h>
 #include <limits.h>
 #include <stdarg.h>
-#ifndef _WIN32_WCE
-#include <signal.h>
-#endif
 
 #define I_HIDE_POINTERS        /* To make GC_call_with_alloc_lock visible */
 #include "private/gc_pmark.h"
 
+#ifndef MSWINCE
+# include <signal.h>
+#endif
+
 #ifdef GC_SOLARIS_THREADS
 # include <sys/syscall.h>
 #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 <crtdbg.h>
+
+# if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
+#   include <crtdbg.h>
 # 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;
index 26135e9d62930535bc4e41a0a5bfc7700e234857..3cc6d4977be1e2f3fd1dfea5b7263b058704689a 100644 (file)
--- 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 */
index 6650a72defa6a677d4dcfe72773a7ade11980b25..b32dac1ff20998ea0b0eba0a7466cd8031a0d6f9 100644 (file)
@@ -39,7 +39,7 @@
 #   include <stdlib.h>
 # endif
 # include <stdio.h>
-# ifdef _WIN32_WCE
+# if defined(_WIN32_WCE) && !defined(__GNUC__)
 #   include <winbase.h>
 /* #   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;
 }
index 9e9a0d7838285b55590c7bb0a964286645801f73..00b5d00111dee84fbc0daa620433365f23f744f8 100644 (file)
@@ -36,7 +36,7 @@
 #endif
 
 #ifdef GC_PTHREADS
-# include <errno.h>
+# include <errno.h> /* 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 <pthread.h>
+
+# 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 */,