+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)
# 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.)
# 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)
# 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. */
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");
}
#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)
# 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;
/* 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
# 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;
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
}
}
+#ifdef WRAP_MARK_SOME
-#if defined(MSWIN32) && defined(__GNUC__) && !defined(_WIN64)
+# if (defined(MSWIN32) || defined(MSWINCE)) && defined(__GNUC__)
typedef struct {
EXCEPTION_REGISTRATION ex_reg;
/* 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 */
/* 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. */
/* 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);
#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
# 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");
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();
#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;
# endif
#else
# define IF_NEED_TO_LOCK(x)
+#endif
+
+#ifndef _MAX_PATH
+# define _MAX_PATH MAX_PATH
#endif
STATIC HANDLE GC_CreateLogFile(void)
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;
/* 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;
}
# 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)
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 */
# 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 */
# 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 */
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, */
} 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 */
# include <stdlib.h>
# endif
# include <stdio.h>
-# ifdef _WIN32_WCE
+# if defined(_WIN32_WCE) && !defined(__GNUC__)
# include <winbase.h>
/* # define assert ASSERT */
# else
*/
#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
{
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;
}
#endif
#ifdef GC_PTHREADS
-# include <errno.h>
+# include <errno.h> /* for EAGAIN */
/* Cygwin-specific forward decls */
# undef pthread_create
# 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 */
/* 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
/* 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) { \
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 */
/* 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. */
prev = p;
p = p -> next;
}
- CloseHandle(p->handle);
+# ifndef MSWINCE
+ CloseHandle(p->handle);
+# endif
if (prev == 0) {
GC_threads[hv] = p -> next;
} else {
# 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
/* 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
# 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 */
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;
}
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;
} 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 */
#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
/* 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; */
STATIC void start_mark_threads(void)
{
- unsigned i;
+ int i;
pthread_attr_t attr;
pthread_t new_thread;
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);
}
}
-#else /* ! GC_PTHREADS */
+#else /* ! GC_PTHREADS_PARAMARK */
# ifndef MARK_THREAD_STACK_SIZE
# define MARK_THREAD_STACK_SIZE 0 /* default value */
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); */
- }
}
}
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)
{
/* 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. */
}
/* 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)
/* Defined in os_dep.c */
extern GC_bool GC_wnt;
-#endif /* ! GC_PTHREADS */
+#endif /* ! GC_PTHREADS_PARAMARK */
#endif /* PARALLEL_MARK */
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);
}
#endif /* !GC_PTHREADS */
-#ifdef MSWINCE
+#if defined(MSWINCE) && !defined(GC_DLL)
typedef struct {
HINSTANCE hInstance;
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)
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();
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. */
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");
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;
} 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 */
}
/* 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)
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 */,