diff options
-rw-r--r-- | ChangeLog | 128 | ||||
-rw-r--r-- | Makefile.direct | 5 | ||||
-rw-r--r-- | dbg_mlc.c | 22 | ||||
-rw-r--r-- | dyn_load.c | 8 | ||||
-rw-r--r-- | include/gc.h | 38 | ||||
-rw-r--r-- | include/gc_config_macros.h | 6 | ||||
-rw-r--r-- | include/private/gc_locks.h | 9 | ||||
-rw-r--r-- | include/private/gc_priv.h | 12 | ||||
-rw-r--r-- | include/private/gcconfig.h | 9 | ||||
-rw-r--r-- | include/private/thread_local_alloc.h | 9 | ||||
-rw-r--r-- | malloc.c | 24 | ||||
-rw-r--r-- | mark.c | 8 | ||||
-rw-r--r-- | misc.c | 100 | ||||
-rw-r--r-- | os_dep.c | 11 | ||||
-rw-r--r-- | tests/test.c | 88 | ||||
-rw-r--r-- | thread_local_alloc.c | 6 | ||||
-rw-r--r-- | win32_threads.c | 168 |
17 files changed, 464 insertions, 187 deletions
@@ -1,5 +1,133 @@ 2009-09-10 Ivan Maidanski <ivmai@mail.ru> + (diff114a, diff114b, diff114c) + + * dbg_mlc.c: Guard include <errno.h> with ifndef MSWINCE; include + "private/dbg_mlc.h" before it. + * malloc.c: Ditto. + * dbg_mlc.c (GC_debug_strdup): Use memcpy() instead of strcpy() + for WinCE (since deprecated); evaluate strlen() only once; don't + set errno for WinCE. + * malloc.c (GC_strdup): Ditto. + * dyn_load.c (GC_wnt): Define as macro (FALSE) for WinCE. + * include/gc.h (GC_unregister_my_thread): Refine the comment. + * include/gc.h (GC_uintptr_t, GC_beginthreadex, GC_endthreadex): + Don't declare for WinCE. + * include/gc.h (GC_WINMAIN_WINCE_LPTSTR): New macro (WinCE only). + * include/gc.h (GC_WinMain): Remove GC_API. + * include/gc.h (GC_WinMain): Use GC_WINMAIN_WINCE_LPTSTR for + lpCmdLine. + * tests/test.c (GC_WinMain): Ditto. + * win32_threads.c (main_thread_args, GC_WinMain): Ditto. + * include/gc_config_macros.h (ptrdiff_t): Guard with + ifndef _PTRDIFF_T_DEFINED; define _PTRDIFF_T_DEFINED macro. + * include/private/gc_locks.h: Guard include "atomic_ops.h" with + ifdef GC_PTHREADS (and not GC_WIN32_THREADS). + * mark.c: Include "atomic_ops.h" if PARALLEL_MARK. + * thread_local_alloc.c: Include "atomic_ops.h" if GC_GCJ_SUPPORT. + * win32_threads.c: Include "atomic_ops.h" if MPROTECT_VDB. + * include/private/gc_locks.h: Use include "atomic_ops.h" instead + of include <atomic_ops.h>. + * include/private/gc_priv.h: Ditto. + * include/private/gc_locks.h (GC_allocate_ml, GC_need_to_lock): + Don't export (replace GC_API to "extern"). + * win32_threads.c (GC_allocate_ml): Don't export. + * include/private/gc_priv.h (DebugBreak): Define as macro for + WinCE (if not UNDER_CE and DebugBreak is not defined yet). + * include/private/gc_priv.h (UNALIGNED): Rename to UNALIGNED_PTRS + (since "UNALIGNED" is defined in winnt.h of WinCE). + * mark.c (UNALIGNED): Ditto. + * include/private/gcconfig.h (ARM32): Recognize _M_ARM and _ARM_. + * include/private/gcconfig.h (ALIGNMENT): Check always defined. + * include/private/gcconfig.h: Allow GC_WIN32_THREADS for WinCE. + * include/private/thread_local_alloc.h: Define USE_WIN32_SPECIFIC + for WinCE (since __declspec(thread) is unsupported). + * include/private/thread_local_alloc.h (TLS_OUT_OF_INDEXES): + Define for WinCE (if undefined). + * malloc.c (GC_malloc): Remove outdated comment about disabling + signals. + * misc.c: Don't include <tchar.h> (since not used anymore and may + break TEXT() macro defined in winnt.h). + * misc.c (GC_init_inner): Don't use GetModuleHandle() and + InitializeCriticalSectionAndSpinCount() for WinCE. + * misc.c (GC_init_inner): Replace GetModuleHandleA() with + GetModuleHandle() (and use TEXT() macro controlled by UNICODE). + * misc.c (LOG_FILE): Remove unused macro; don't use _T() macro. + * misc.c (GC_CreateLogFile): New static function (Win32/WinCE + only); move the code from GC_write(); replace GETENV() with + GetEnvironmentVariable(); replace CreateFileA() with + CreateFile(); use TEXT() macro (for Unicode support); replace + strcat() with memcpy() (since deprecated in WinCE). + * misc.c (GC_write): Define as STATIC. + * win32_threads.c (GC_attached_thread): Ditto. + * misc.c (GC_write): Use GC_CreateLogFile(). + * misc.c: Define vsnprintf macro as StringCchVPrintfA for WinCE. + * misc.c (GC_abort): Try to invoke MessageBoxA() dynamically + (Win32 only) if DONT_USE_USER32_DLL is defined. + * misc.c (GC_abort): Duplicate msg to GC log file (for Win32 and + WinCE). + * misc.c (GC_abort): Use a more user-friendly abort if + NO_DEBUGGING (Win32 only). + * os_dep.c: Include "atomic_ops.h" only if MPROTECT_VDB (and + THREADS). + * os_dep.c (detect_GetWriteWatch): Use TEXT() for GetModuleHandle + (for Unicode support); check GetModuleHandle() result. + * tests/test.c: Don't define assert for WinCE (since may be + redefined by "assert.h" included from libatomic_ops). + * tests/test.c (FAIL): Define as ABORT for all targets (except + for PCR). + * tests/test.c (n_tests): Don't use AO_t. + * tests/test.c (check_heap_stats): Don't cast n_tests. + * tests/test.c (inc_int_counter): New function (for n_tests atomic + incrementation). + * tests/test.c (run_one_test): Test GC_memalign() for all targets. + * tests/test.c (run_one_test): Avoid unbalanced brackets in + #if-#else-#endif blocks. + * tests/test.c (run_one_test): Replace AO_fetch_and_add1() and + private LOCK/UNLOCK with GC_call_with_alloc_lock(inc_int_counter). + * tests/test.c (check_heap_stats): Replace + "if (sizeof(char *) > 4)" with "#if CPP_WORDSZ == 64" to suppress + "unreachable code" compiler warning. + * tests/test.c (WinMain): Set cmd type to LPWSTR (for WinCE + "UNDER_CE" mode); else use LPSTR type (for Win32 and WinCE). + * tests/test.c (thr_window): Replace "L" string prefix with + TEXT(). + * thread_local_alloc.c: Check THREADS is defined (to prevent other + compiler errors and warnings otherwise). + * tests/test.c (WinMain): Recognize GC_NO_DLLMAIN macro (for + GC_use_DllMain()). + * Makefile.direct (GC_NO_DLLMAIN, DONT_IMPORT_GETCURTHREAD): Add + the comments for. + * win32_threads.c (GC_register_my_thread_inner): Recognize + DONT_IMPORT_GETCURTHREAD macro. + * win32_threads.c: Recognize GC_NO_DLLMAIN macro (to exclude + DllMain support if needed). + * win32_threads.c (GC_NO_DLLMAIN): Define implicitly if DllMain + thread registration is unsupported for a given configuration. + * win32_threads.c (GC_use_DllMain): Update the comment; refine + ABORT message. + * win32_threads.c (GC_use_DllMain, + GC_started_thread_while_stopped, GC_register_my_thread_inner, + GC_lookup_thread_inner, GC_delete_gc_thread, + GC_allow_register_threads, GC_lookup_pthread, + GC_push_thread_structures, GC_stop_world, GC_push_all_stacks): + Check for GC_NO_DLLMAIN. + * win32_threads.c (GC_Thread_Rep.tm_in_use, GC_attached_thread, + DllMain): Don't define if GC_NO_DLLMAIN. + * win32_threads.c (GC_stop_world): Declare "i" and "max" local + vars only if not GC_NO_DLLMAIN (to suppress compiler warning). + * win32_threads.c (GC_mark_thread, start_mark_threads): Use + CreateThread() instead of _beginthreadex() for WinCE. + * win32_threads.c (MARK_THREAD_STACK_SIZE, WINCE_MAIN_STACK_SIZE): + New macros defined (used by start_mark_threads(), WinMain()). + * win32_threads.c (GC_thr_init): Exclude parallel-specific code on + WinCE for now (since getenv(), GetProcessAffinityMask() and + SignalObjectAndWait() are missing on WinCE). + * win32_threads.c (GC_thr_init): replace GetModuleHandleA() with + GetModuleHandle(); replace CreateEventA() with CreateEvent(); use + TEXT() macro (for Unicode support). + +2009-09-10 Ivan Maidanski <ivmai@mail.ru> (diff113) * include/gc.h (GC_has_static_roots_func): New typedef (user filter diff --git a/Makefile.direct b/Makefile.direct index 81003447..b1c4cc12 100644 --- a/Makefile.direct +++ b/Makefile.direct @@ -330,6 +330,11 @@ HOSTCFLAGS=$(CFLAGS) # -DGC_PREFER_MPROTECT_VDB Choose MPROTECT_VDB manually in case of multiple # virtual dirty bit strategies are implemented (at present useful on Win32 # 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. # CXXFLAGS= $(CFLAGS) @@ -15,10 +15,13 @@ * modified is included with the above copyright notice. */ -#include <errno.h> -#include <string.h> #include "private/dbg_mlc.h" +#ifndef MSWINCE +# include <errno.h> +#endif +#include <string.h> + void GC_default_print_heap_obj_proc(ptr_t p); GC_API void GC_CALL GC_register_finalizer_no_order (void * obj, GC_finalization_proc fn, void * cd, @@ -641,13 +644,22 @@ GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS) GC_API char * GC_CALL GC_debug_strdup(const char *str, GC_EXTRA_PARAMS) { char *copy; + size_t lb; if (str == NULL) return NULL; - copy = GC_debug_malloc_atomic(strlen(str) + 1, OPT_RA s, i); + lb = strlen(str) + 1; + copy = GC_debug_malloc_atomic(lb, OPT_RA s, i); if (copy == NULL) { - errno = ENOMEM; +# ifndef MSWINCE + errno = ENOMEM; +# endif return NULL; } - strcpy(copy, str); +# ifndef MSWINCE + strcpy(copy, str); +# else + /* strcpy() is deprecated in WinCE */ + memcpy(copy, str, lb); +# endif return copy; } @@ -859,8 +859,12 @@ void GC_register_dynamic_libraries(void) } # endif /* DEBUG_VIRTUALQUERY */ - extern GC_bool GC_wnt; /* Is Windows NT derivative. */ - /* Defined and set in os_dep.c. */ +# ifdef MSWINCE +# define GC_wnt FALSE +# else + extern GC_bool GC_wnt; /* Is Windows NT derivative. */ + /* Defined and set in os_dep.c. */ +# endif void GC_register_dynamic_libraries(void) { diff --git a/include/gc.h b/include/gc.h index 3a0f95e2..9110bf0b 100644 --- a/include/gc.h +++ b/include/gc.h @@ -962,7 +962,8 @@ GC_API int GC_CALL GC_register_my_thread(struct GC_stack_base *); /* Specifically, if it wants to return or otherwise communicate a */ /* pointer to the garbage-collected heap to another thread, it must */ /* do this before calling GC_unregister_my_thread, most probably */ -/* by saving it in a global data structure. */ +/* by saving it in a global data structure. Must not be called inside */ +/* a GC callback function (except for GC_call_with_stack_base() one). */ GC_API int GC_CALL GC_unregister_my_thread(void); /* Attempt to fill in the GC_stack_base structure with the stack base */ @@ -1142,6 +1143,10 @@ GC_API void GC_CALL GC_register_has_static_roots_callback( DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); + GC_API void WINAPI GC_ExitThread(DWORD /* dwExitCode */); + +# if !defined(_WIN32_WCE) + # if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \ && !defined(UINTPTR_MAX) typedef GC_word GC_uintptr_t; @@ -1156,21 +1161,22 @@ GC_API void GC_CALL GC_register_has_static_roots_callback( GC_API void GC_CALL GC_endthreadex(unsigned retval); - GC_API void WINAPI GC_ExitThread(DWORD dwExitCode); - -# if defined(_WIN32_WCE) - /* - * win32_threads.c implements the real WinMain, which will start a new thread - * to call GC_WinMain after initializing the garbage collector. - */ - GC_API int WINAPI GC_WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPWSTR lpCmdLine, - int nCmdShow ); -# ifndef GC_BUILD -# define WinMain GC_WinMain -# endif +# else + /* win32_threads.c implements the real WinMain, which will start */ + /* a new thread to call GC_WinMain after initializing the garbage */ + /* collector. */ +# ifdef UNDER_CE +# define GC_WINMAIN_WINCE_LPTSTR LPWSTR +# else +# define GC_WINMAIN_WINCE_LPTSTR LPSTR +# endif + /* not exported (since defined outside GC by an application) */ + int WINAPI GC_WinMain( + HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, + GC_WINMAIN_WINCE_LPTSTR /* lpCmdLine */, int /* nCmdShow */); +# ifndef GC_BUILD +# define WinMain GC_WinMain +# endif # endif /* defined(_WIN32_WCE) */ #endif /* !GC_NO_THREAD_DECLS */ diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h index ac56b719..7295ad41 100644 --- a/include/gc_config_macros.h +++ b/include/gc_config_macros.h @@ -143,7 +143,11 @@ # else /* ! _WIN32_WCE */ /* Yet more kludges for WinCE */ # include <stdlib.h> /* size_t is defined here */ - typedef long ptrdiff_t; /* ptrdiff_t is not defined */ +# ifndef _PTRDIFF_T_DEFINED + /* ptrdiff_t is not defined */ +# define _PTRDIFF_T_DEFINED + typedef long ptrdiff_t; +# endif # endif #if defined(_DLL) && !defined(GC_NOT_DLL) && !defined(GC_DLL) diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h index 467c1a53..7a9a6689 100644 --- a/include/private/gc_locks.h +++ b/include/private/gc_locks.h @@ -27,7 +27,10 @@ * in assertions, and may return TRUE in the "dont know" case. */ # ifdef THREADS -# include <atomic_ops.h> + +# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) +# include "atomic_ops.h" +# endif GC_API void GC_CALL GC_noop1(word); # ifdef PCR @@ -52,7 +55,7 @@ # include <windows.h> # define NO_THREAD (DWORD)(-1) extern DWORD GC_lock_holder; - GC_API CRITICAL_SECTION GC_allocate_ml; + extern CRITICAL_SECTION GC_allocate_ml; # ifdef GC_ASSERTIONS # define UNCOND_LOCK() \ { EnterCriticalSection(&GC_allocate_ml); \ @@ -192,7 +195,7 @@ # endif /* !THREADS */ #if defined(UNCOND_LOCK) && !defined(LOCK) - GC_API GC_bool GC_need_to_lock; + extern GC_bool GC_need_to_lock; /* At least two thread running; need to lock. */ # define LOCK() if (GC_need_to_lock) { UNCOND_LOCK(); } # define UNLOCK() if (GC_need_to_lock) { UNCOND_UNLOCK(); } diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 3976ddd8..d9f5dd22 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -334,6 +334,12 @@ void GC_print_callers(struct callinfo info[NFRAMES]); # ifdef PCR # define ABORT(s) PCR_Base_Panic(s) # else +# if defined(MSWINCE) && !defined(UNDER_CE) && !defined(DebugBreak) + /* This simplifies linking for WinCE (and, probably, doesn't */ + /* hurt debugging much); use -DDebugBreak=DebugBreak to override */ + /* this behavior if really needed. */ +# define DebugBreak() _exit(-1) /* there is no abort() in WinCE */ +# endif # ifdef SMALL_CONFIG # if defined(MSWIN32) || defined(MSWINCE) # define ABORT(msg) DebugBreak() @@ -444,7 +450,7 @@ extern GC_warn_proc GC_current_warn_proc; # define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */ # define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */ # if ALIGNMENT != 4 -# define UNALIGNED +# define UNALIGNED_PTRS # endif #endif @@ -454,7 +460,7 @@ extern GC_warn_proc GC_current_warn_proc; # define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */ # define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */ # if ALIGNMENT != 8 -# define UNALIGNED +# define UNALIGNED_PTRS # endif #endif @@ -682,7 +688,7 @@ typedef word page_hash_table[PHT_SIZE]; # endif #ifdef PARALLEL_MARK -# include <atomic_ops.h> +# include "atomic_ops.h" typedef AO_t counter_t; #else typedef size_t counter_t; diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index e8c261d6..6b5cedc7 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -374,7 +374,7 @@ # if defined(x86) # define I386 # endif -# if defined(ARM) +# if defined(_M_ARM) || defined(ARM) || defined(_ARM_) # define ARM32 # endif # define MSWINCE @@ -2100,6 +2100,10 @@ -> bad word size # endif +# ifndef ALIGNMENT + --> undefined ALIGNMENT +# endif + # ifdef PCR # undef DYNAMIC_LOADING # undef STACKBOTTOM @@ -2211,7 +2215,8 @@ # if defined(GC_GNU_THREADS) && !defined(HURD) --> inconsistent configuration # endif -# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) +# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) \ + && !defined(MSWINCE) --> inconsistent configuration # endif diff --git a/include/private/thread_local_alloc.h b/include/private/thread_local_alloc.h index 32b6a3e5..9bfbcb52 100644 --- a/include/private/thread_local_alloc.h +++ b/include/private/thread_local_alloc.h @@ -26,7 +26,7 @@ #include "gc_inline.h" -# if defined USE_HPUX_TLS +# if defined(USE_HPUX_TLS) # error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS # endif @@ -34,7 +34,8 @@ !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) && \ !defined(USE_CUSTOM_SPECIFIC) # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) -# if defined(__GNUC__) /* Fixed for versions past 2.95? */ +# if defined(__GNUC__) /* Fixed for versions past 2.95? */ \ + || defined(MSWINCE) # define USE_WIN32_SPECIFIC # else # define USE_WIN32_COMPILER_TLS @@ -107,6 +108,10 @@ typedef struct thread_local_freelists { # define GC_getspecific TlsGetValue # define GC_setspecific(key, v) !TlsSetValue(key, v) /* We assume 0 == success, msft does the opposite. */ +# ifndef TLS_OUT_OF_INDEXES + /* this is currently missing in WinCE */ +# 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? \ @@ -13,10 +13,13 @@ * modified is included with the above copyright notice. */ +#include "private/gc_priv.h" + #include <stdio.h> #include <string.h> -#include <errno.h> -#include "private/gc_priv.h" +#ifndef MSWINCE +# include <errno.h> +#endif extern void * GC_clear_stack(void *); /* in misc.c, behaves like identity */ void GC_extend_size_map(size_t); /* in misc.c. */ @@ -236,13 +239,21 @@ void * GC_generic_malloc(size_t lb, int k) GC_API char * GC_CALL GC_strdup(const char *s) { char *copy; - + size_t lb; if (s == NULL) return NULL; - if ((copy = GC_malloc_atomic(strlen(s) + 1)) == NULL) { - errno = ENOMEM; + lb = strlen(s) + 1; + if ((copy = GC_malloc_atomic(lb)) == NULL) { +# ifndef MSWINCE + errno = ENOMEM; +# endif return NULL; } - strcpy(copy, s); +# ifndef MSWINCE + strcpy(copy, s); +# else + /* strcpy() is deprecated in WinCE */ + memcpy(copy, s, lb); +# endif return copy; } @@ -266,7 +277,6 @@ GC_API char * GC_CALL GC_strdup(const char *s) UNLOCK(); return(GENERAL_MALLOC((word)lb, NORMAL)); } - /* See above comment on signals. */ GC_ASSERT(0 == obj_link(op) || ((word)obj_link(op) <= (word)GC_greatest_plausible_heap_addr @@ -113,8 +113,6 @@ mse * GC_mark_stack_limit; size_t GC_mark_stack_size = 0; #ifdef PARALLEL_MARK -# include "atomic_ops.h" - mse * volatile GC_mark_stack_top; /* Updated only with mark lock held, but read asynchronously. */ volatile AO_t GC_first_nonempty; @@ -1640,7 +1638,7 @@ void GC_push_marked1(struct hblk *h, hdr *hhdr) } -#ifndef UNALIGNED +#ifndef UNALIGNED_PTRS /* Push all objects reachable from marked objects in the given block */ /* of size 2 (granules) objects. */ @@ -1738,7 +1736,7 @@ void GC_push_marked4(struct hblk *h, hdr *hhdr) #endif /* GC_GRANULE_WORDS < 4 */ -#endif /* UNALIGNED */ +#endif /* UNALIGNED_PTRS */ #endif /* USE_PUSH_MARKED_ACCELERATORS */ @@ -1769,7 +1767,7 @@ void GC_push_marked(struct hblk *h, hdr *hhdr) case 1: GC_push_marked1(h, hhdr); break; -# if !defined(UNALIGNED) +# if !defined(UNALIGNED_PTRS) case 2: GC_push_marked2(h, hhdr); break; @@ -32,7 +32,6 @@ # define WIN32_LEAN_AND_MEAN # define NOSERVICE # include <windows.h> -# include <tchar.h> #endif #if defined(UNIX_LIKE) || defined(CYGWIN32) @@ -523,8 +522,9 @@ void GC_init_inner(void) # endif # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) if (!GC_is_initialized) { +# ifndef MSWINCE BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL; - HMODULE hK32 = GetModuleHandleA("kernel32.dll"); + HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll")); if (hK32) pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD)) GetProcAddress (hK32, @@ -532,7 +532,8 @@ void GC_init_inner(void) if (pfn) pfn(&GC_allocate_ml, 4000); else - InitializeCriticalSection (&GC_allocate_ml); +# endif /* !MSWINCE */ + /* else */ InitializeCriticalSection (&GC_allocate_ml); } #endif /* MSWIN32 */ # if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS) @@ -869,9 +870,6 @@ out: # if defined(_MSC_VER) && defined(_DEBUG) # include <crtdbg.h> # endif -# ifdef OLD_WIN32_LOG_FILE -# define LOG_FILE _T("gc.log") -# endif STATIC HANDLE GC_stdout = 0; @@ -894,7 +892,37 @@ out: # define IF_NEED_TO_LOCK(x) #endif - int GC_write(const char *buf, size_t len) + STATIC HANDLE GC_CreateLogFile(void) + { +# if !defined(NO_GETENV) || !defined(OLD_WIN32_LOG_FILE) + TCHAR logPath[_MAX_PATH + sizeof(".log")]; +# endif + /* Use GetEnvironmentVariable instead of GETENV() for unicode support. */ +# ifndef NO_GETENV + if (GetEnvironmentVariable(TEXT("GC_LOG_FILE"), logPath, + _MAX_PATH + 1) - 1U >= (DWORD)_MAX_PATH) +# endif + { + /* Env var not found or its value too long. */ +# ifdef OLD_WIN32_LOG_FILE + return CreateFile(TEXT("gc.log"), GENERIC_WRITE, FILE_SHARE_READ, + NULL /* lpSecurityAttributes */, CREATE_ALWAYS, + FILE_FLAG_WRITE_THROUGH, NULL /* hTemplateFile */); +# else + /* strcat/wcscat() are deprecated on WinCE, so use memcpy() */ + memcpy(&logPath[GetModuleFileName(NULL /* hModule */, logPath, + _MAX_PATH + 1)], + TEXT(".log"), sizeof(TEXT(".log"))); +# endif + } +# if !defined(NO_GETENV) || !defined(OLD_WIN32_LOG_FILE) + return CreateFile(logPath, GENERIC_WRITE, FILE_SHARE_READ, + NULL /* lpSecurityAttributes */, CREATE_ALWAYS, + FILE_FLAG_WRITE_THROUGH, NULL /* hTemplateFile */); +# endif + } + + STATIC int GC_write(const char *buf, size_t len) { BOOL tmp; DWORD written; @@ -905,22 +933,7 @@ out: IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs)); return -1; } else if (GC_stdout == 0) { - char * file_name = GETENV("GC_LOG_FILE"); - char logPath[_MAX_PATH + 5]; - - if (0 == file_name) { -# ifdef OLD_WIN32_LOG_FILE - strcpy(logPath, LOG_FILE); -# else - GetModuleFileNameA(NULL, logPath, _MAX_PATH); - strcat(logPath, ".log"); -# endif - file_name = logPath; - } - GC_stdout = CreateFileA(file_name, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, - NULL); + GC_stdout = GC_CreateLogFile(); if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed"); } @@ -967,7 +980,7 @@ STATIC int GC_tmp; /* Should really be local ... */ #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \ && !defined(MACOS) && !defined(ECOS) && !defined(NOSYS) -int GC_write(int fd, const char *buf, size_t len) +STATIC int GC_write(int fd, const char *buf, size_t len) { register int bytes_written = 0; register int result; @@ -987,7 +1000,7 @@ int GC_write(int fd, const char *buf, size_t len) #endif /* UN*X */ #ifdef ECOS -int GC_write(int fd, const char *buf, size_t len) +STATIC int GC_write(int fd, const char *buf, size_t len) { _Jv_diag_write (buf, len); return len; @@ -995,7 +1008,7 @@ int GC_write(int fd, const char *buf, size_t len) #endif #ifdef NOSYS -int GC_write(int fd, const char *buf, size_t len) +STATIC int GC_write(int fd, const char *buf, size_t len) { /* No writing. */ return len; @@ -1018,7 +1031,12 @@ int GC_write(int fd, const char *buf, size_t len) #define BUFSZ 1024 #ifdef _MSC_VER -# define vsnprintf _vsnprintf +# ifdef MSWINCE + /* _vsnprintf is deprecated in WinCE */ +# define vsnprintf StringCchVPrintfA +# else +# define vsnprintf _vsnprintf +# endif #endif /* A version of printf that is unlikely to call malloc, and is thus safer */ /* to call from the collector in case malloc has been bound to GC_malloc. */ @@ -1121,15 +1139,30 @@ GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void) #if !defined(PCR) && !defined(SMALL_CONFIG) void GC_abort(const char *msg) { -# if defined(MSWIN32) && !defined(DONT_USE_USER32_DLL) - (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK); -# else +# if defined(MSWIN32) +# ifndef DONT_USE_USER32_DLL + /* Use static binding to "user32.dll". */ + (void)MessageBoxA(NULL, msg, "Fatal error in GC", MB_ICONERROR|MB_OK); +# else + /* This simplifies linking - resolve "MessageBoxA" at run-time. */ + HINSTANCE hU32 = LoadLibrary(TEXT("user32.dll")); + if (hU32) { + FARPROC pfn = GetProcAddress(hU32, "MessageBoxA"); + if (pfn) + (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)( + NULL /* hWnd */, msg, "Fatal error in GC", + MB_ICONERROR | MB_OK); + (void)FreeLibrary(hU32); + } +# endif + /* Also duplicate msg to GC log file. */ +# endif /* Avoid calling GC_err_printf() here, as GC_abort() could be */ /* called from it. Note 1: this is not an atomic output. */ /* Note 2: possible write errors are ignored. */ if (WRITE(GC_stderr, (void *)msg, strlen(msg)) >= 0) (void)WRITE(GC_stderr, (void *)("\n"), 1); -# endif + if (GETENV("GC_LOOP_ON_ABORT") != NULL) { /* In many cases it's easier to debug a running process. */ /* It's arguably nicer to sleep, but that makes it harder */ @@ -1137,7 +1170,10 @@ void GC_abort(const char *msg) /* about threads. */ for(;;) {} } -# if defined(MSWIN32) || defined(MSWINCE) +# if defined(MSWIN32) && defined(NO_DEBUGGING) + /* A more user-friendly abort after showing fatal message. */ + _exit(-1); /* exit on error without running "at-exit" callbacks */ +# elif defined(MSWIN32) || defined(MSWINCE) DebugBreak(); # else (void) abort(); @@ -15,7 +15,8 @@ */ # include "private/gc_priv.h" -# ifdef THREADS + +# if defined(THREADS) && defined(MPROTECT_VDB) # include "atomic_ops.h" # endif @@ -1283,6 +1284,7 @@ void GC_register_data_segments(void) static void detect_GetWriteWatch(void) { static GC_bool done; + HMODULE hK32; if (done) return; @@ -1306,9 +1308,10 @@ void GC_register_data_segments(void) } # endif - GetWriteWatch_func = (GetWriteWatch_type) - GetProcAddress(GetModuleHandle("kernel32.dll"), "GetWriteWatch"); - if (GetWriteWatch_func != NULL) { + hK32 = GetModuleHandle(TEXT("kernel32.dll")); + if (hK32 != (HMODULE)0 && + (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32, + "GetWriteWatch")) != NULL) { /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */ /* as some versions of kernel32.dll have one but not the */ /* other, making the feature completely broken. */ diff --git a/tests/test.c b/tests/test.c index 79ea8a04..bfe9c49f 100644 --- a/tests/test.c +++ b/tests/test.c @@ -37,7 +37,7 @@ # include <stdio.h> # ifdef _WIN32_WCE # include <winbase.h> -# define assert ASSERT +/* # define assert ASSERT */ # else # include <assert.h> /* Not normally used, but handy for debugging. */ # endif @@ -130,14 +130,7 @@ int realloc_count = 0; # ifdef PCR # define FAIL (void)abort() # else -# ifdef MSWINCE -# define FAIL DebugBreak() -# else -# ifdef SMALL_CONFIG - void GC_abort(const char * msg); -# endif -# define FAIL GC_abort("Test failed"); -# endif +# define FAIL ABORT("Test failed") # endif #endif /* !AMIGA_FASTALLOC */ @@ -519,11 +512,11 @@ void reverse_test(void) /* Win32S only allows 128K stacks */ # define BIG 1000 # else -# if defined PCR +# if defined(PCR) /* PCR default stack is 100K. Stack frames are up to 120 bytes. */ # define BIG 700 # else -# if defined MSWINCE +# if defined(MSWINCE) /* WinCE only allows 64K stacks */ # define BIG 500 # else @@ -881,11 +874,7 @@ void tree_test(void) # endif } -#if defined(THREADS) && defined(AO_HAVE_fetch_and_add1_full) - AO_t n_tests = 0; /* Updated by AO_fetch_and_add1_full(). */ -#else - unsigned n_tests = 0; -#endif +unsigned n_tests = 0; GC_word bm_huge[10] = { 0xffffffff, @@ -1009,6 +998,12 @@ static void uniq(void *p, ...) { # define TEST_FAIL_COUNT(n) (fail_count >= (n)) #endif +void * GC_CALLBACK inc_int_counter(void *pcounter) +{ + ++(*(int *)pcounter); + return NULL; +} + void run_one_test(void) { # ifndef DBG_HDRS_ALL @@ -1103,7 +1098,6 @@ void run_one_test(void) "GC_is_valid_displacement produced incorrect result\n"); FAIL; } -# if !defined(MSWINCE) { size_t i; @@ -1113,14 +1107,14 @@ void run_one_test(void) if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL; } } -# endif # ifndef ALL_INTERIOR_POINTERS # if defined(RS6000) || defined(POWERPC) - if (!TEST_FAIL_COUNT(1)) { + if (!TEST_FAIL_COUNT(1)) # else if ((GC_all_interior_pointers && !TEST_FAIL_COUNT(1)) - || (!GC_all_interior_pointers && !TEST_FAIL_COUNT(2))) { + || (!GC_all_interior_pointers && !TEST_FAIL_COUNT(2))) # endif + { GC_printf("GC_is_valid_displacement produced wrong failure indication\n"); FAIL; } @@ -1195,16 +1189,9 @@ void run_one_test(void) GC_log_printf("-------------Finished second reverse_test at time %u (%p)\n", (unsigned) time_diff, &start_time); } -# if defined(THREADS) && defined(AO_HAVE_fetch_and_add1_full) - /* Use AO_fetch_and_add1_full() if available. */ - /* GC_allocate_ml may not always be visible outside GC. */ - (void)AO_fetch_and_add1_full(&n_tests); -# else - LOCK(); - /* AO_fetch_and_add1 is not always available. */ - n_tests++; - UNLOCK(); -# endif + /* GC_allocate_ml and GC_need_to_lock are no longer exported, and */ + /* AO_fetch_and_add1() may be unavailable to update a counter. */ + (void)GC_call_with_alloc_lock(inc_int_counter, &n_tests); # if defined(THREADS) && defined(HANDLE_FORK) if (fork() == 0) { GC_gcollect(); @@ -1234,17 +1221,17 @@ void check_heap_stats(void) /* these may be particularly dubious, since empirically the */ /* heap tends to grow largely as a result of the GC not */ /* getting enough cycles. */ - if (sizeof(char *) > 4) { +# if CPP_WORDSZ == 64 max_heap_sz = 4500000; - } else { +# else max_heap_sz = 2800000; - } +# endif # else - if (sizeof(char *) > 4) { +# if CPP_WORDSZ == 64 max_heap_sz = 19000000; - } else { +# else max_heap_sz = 12000000; - } +# endif # endif # ifdef GC_DEBUG max_heap_sz *= 2; @@ -1265,7 +1252,7 @@ void check_heap_stats(void) # endif GC_invoke_finalizers(); } - (void)GC_printf("Completed %u tests\n", (unsigned) n_tests); + (void)GC_printf("Completed %u tests\n", n_tests); (void)GC_printf("Allocated %d collectable objects\n", collectable_count); (void)GC_printf("Allocated %d uncollectable objects\n", uncollectable_count); @@ -1353,8 +1340,10 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p) #if !defined(PCR) \ && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \ || defined(LINT) -#if defined(MSWIN32) && !defined(__MINGW32__) - int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPTSTR cmd, int n) +#if defined(MSWINCE) && defined(UNDER_CE) + int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPWSTR cmd, int n) +#elif defined(MSWIN32) && !defined(__MINGW32__) || defined(MSWINCE) + int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) #else int main(void) #endif @@ -1457,7 +1446,7 @@ DWORD __stdcall thr_window(void *arg) NULL, (HBRUSH)(COLOR_APPWORKSPACE+1), NULL, - L"GCtestWindow" + TEXT("GCtestWindow") }; MSG msg; @@ -1466,8 +1455,8 @@ DWORD __stdcall thr_window(void *arg) win_handle = CreateWindowEx( 0, - L"GCtestWindow", - L"GCtest", + TEXT("GCtestWindow"), + TEXT("GCtest"), 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, @@ -1492,11 +1481,12 @@ DWORD __stdcall thr_window(void *arg) } #endif -# ifdef MSWINCE -int APIENTRY GC_WinMain(HINSTANCE instance, HINSTANCE prev, LPWSTR cmd, int n) -# else -int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) -# endif +#ifdef MSWINCE + int APIENTRY GC_WinMain(HINSTANCE instance, HINSTANCE prev, + GC_WINMAIN_WINCE_LPTSTR cmd, int n) +#else + int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) +#endif { # if NTHREADS > 0 HANDLE h[NTHREADS]; @@ -1506,8 +1496,8 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) HANDLE win_thr_h; # endif DWORD thread_id; - -# if defined(GC_DLL) && !defined(THREAD_LOCAL_ALLOC) && !defined(PARALLEL_MARK) +# if defined(GC_DLL) && !defined(GC_NO_DLLMAIN) && !defined(MSWINCE) \ + && !defined(THREAD_LOCAL_ALLOC) && !defined(PARALLEL_MARK) GC_use_DllMain(); /* Test with implicit thread registration if possible. */ GC_printf("Using DllMain to track threads\n"); # endif diff --git a/thread_local_alloc.c b/thread_local_alloc.c index 0e78f2f6..db217c26 100644 --- a/thread_local_alloc.c +++ b/thread_local_alloc.c @@ -14,6 +14,10 @@ # if defined(THREAD_LOCAL_ALLOC) +#ifndef THREADS +# error "invalid config - THREAD_LOCAL_ALLOC requires GC_THREADS" +#endif + #include "private/thread_local_alloc.h" #include "gc_inline.h" @@ -215,6 +219,8 @@ GC_API void * GC_CALL GC_malloc_atomic(size_t bytes) #ifdef GC_GCJ_SUPPORT +#include "atomic_ops.h" /* for AO_compiler_barrier() */ + #include "include/gc_gcj.h" #ifdef GC_ASSERTIONS diff --git a/win32_threads.c b/win32_threads.c index 75865da2..a7744a35 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -27,11 +27,7 @@ /* Allocation lock declarations. */ #if !defined(USE_PTHREAD_LOCKS) -# if defined(GC_DLL) - __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml; -# else - CRITICAL_SECTION GC_allocate_ml; -# endif + CRITICAL_SECTION GC_allocate_ml; DWORD GC_lock_holder = NO_THREAD; /* Thread id for current holder of allocation lock */ #else @@ -94,8 +90,10 @@ /* DllMain-based thread registration is currently incompatible */ /* with thread-local allocation, pthreads and WinCE. */ -#if defined(GC_DLL) && !defined(MSWINCE) \ +#if defined(GC_DLL) && !defined(GC_NO_DLLMAIN) && !defined(MSWINCE) \ && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS) +# include "atomic_ops.h" + static GC_bool GC_win32_dll_threads = FALSE; /* This code operates in two distinct modes, depending on */ /* the setting of GC_win32_dll_threads. If */ @@ -126,6 +124,9 @@ /* i.e. before any collector or thread calls. We make it a */ /* "dynamic" option only to avoid multiple library versions. */ #else +# ifndef GC_NO_DLLMAIN +# define GC_NO_DLLMAIN +# endif # define GC_win32_dll_threads FALSE # undef MAX_THREADS # define MAX_THREADS 1 /* dll_thread_table[] is always empty. */ @@ -151,28 +152,21 @@ static GC_bool parallel_initialized = FALSE; void GC_init_parallel(void); -/* GC_use_DllMain() is currently incompatible with pthreads. */ -/* It might be possible to get GC_DLL and DllMain-based thread registration */ -/* to work with Cygwin, but if you try, you are on your own. */ -#if defined(GC_DLL) && !defined(GC_PTHREADS) +/* GC_use_DllMain() is currently incompatible with pthreads and WinCE. */ +/* It might be possible to get DllMain-based thread registration to */ +/* work with Cygwin, but if you try, you are on your own. */ +#ifndef GC_NO_DLLMAIN /* Turn on GC_win32_dll_threads */ GC_API void GC_CALL GC_use_DllMain(void) { -# ifdef THREAD_LOCAL_ALLOC - ABORT("Cannot use thread local allocation with DllMain-based " - "thread registration."); - /* Thread-local allocation really wants to lock at thread */ - /* entry and exit. */ -# else GC_ASSERT(!parallel_initialized); GC_win32_dll_threads = TRUE; GC_init_parallel(); -# endif } #else GC_API void GC_CALL GC_use_DllMain(void) { - ABORT("GC not configured as DLL"); + ABORT("GC DllMain-based thread registration unsupported"); } #endif @@ -182,11 +176,13 @@ STATIC DWORD GC_main_thread = 0; struct GC_Thread_Rep { union { - AO_t tm_in_use; /* Updated without lock. */ +# ifndef GC_NO_DLLMAIN + AO_t tm_in_use; /* Updated without lock. */ /* We assert that unused */ /* entries have invalid ids of */ /* zero and zero stack fields. */ /* Used only with GC_win32_dll_threads. */ +# endif struct GC_Thread_Rep * tm_next; /* Hash table link without */ /* GC_win32_dll_threads. */ @@ -250,11 +246,15 @@ volatile GC_bool GC_please_stop = FALSE; * If we notice this in the middle of marking. */ -AO_t GC_attached_thread = FALSE; +#ifndef GC_NO_DLLMAIN + STATIC AO_t GC_attached_thread = FALSE; +#endif + /* Return TRUE if an thread was attached since we last asked or */ /* since GC_attached_thread was explicitly reset. */ GC_bool GC_started_thread_while_stopped(void) { +#ifndef GC_NO_DLLMAIN AO_t result; if (GC_win32_dll_threads) { @@ -264,9 +264,9 @@ GC_bool GC_started_thread_while_stopped(void) AO_store(&GC_attached_thread, FALSE); } return ((GC_bool)result); - } else { - return FALSE; } +#endif + return FALSE; } /* Thread table used if GC_win32_dll_threads is set. */ @@ -360,6 +360,7 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, # endif # endif +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { int i; /* It appears to be unsafe to acquire a lock here, since this */ @@ -400,7 +401,9 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, GC_max_thread_index = MAX_THREADS - 1; } me = dll_thread_table + i; - } else /* Not using DllMain */ { + } else +#endif + /* else */ /* Not using DllMain */ { GC_ASSERT(I_HOLD_LOCK()); GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */ me = GC_new_thread(thread_id); @@ -413,6 +416,12 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, 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(), GetCurrentProcess(), @@ -438,6 +447,7 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, # endif if (me -> stack_base == NULL) ABORT("Bad stack base in GC_register_my_thread_inner"); +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { if (GC_please_stop) { AO_store(&GC_attached_thread, TRUE); @@ -446,7 +456,9 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, /* We'd like to wait here, but can't, since waiting in DllMain */ /* provokes deadlocks. */ /* Thus we force marking to be restarted instead. */ - } else { + } else +#endif + /* else */ { GC_ASSERT(!GC_please_stop); /* Otherwise both we and the thread stopping code would be */ /* holding the allocation lock. */ @@ -477,6 +489,7 @@ STATIC LONG GC_get_max_thread_index(void) /* we hold the allocator lock. */ /* Also used (for assertion checking only) from thread_local_alloc.c. */ GC_thread GC_lookup_thread_inner(DWORD thread_id) { +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); @@ -491,7 +504,9 @@ GC_thread GC_lookup_thread_inner(DWORD thread_id) { } else { return (GC_thread)(dll_thread_table + i); } - } else { + } +#endif + { word hv = ((word)thread_id) % THREAD_TABLE_SZ; register GC_thread p = GC_threads[hv]; @@ -557,6 +572,7 @@ unsigned *GC_check_finalizer_nested(void) STATIC void GC_delete_gc_thread(GC_vthread gc_id) { CloseHandle(gc_id->handle); +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { /* This is intended to be lock-free. */ /* It is either called synchronously from the thread being deleted, */ @@ -571,7 +587,9 @@ STATIC void GC_delete_gc_thread(GC_vthread gc_id) gc_id -> pthread_id.p = NULL; # endif /* GC_WIN32_PTHREADS */ AO_store_release(&(gc_id->in_use), FALSE); - } else { + } else +#endif + /* else */ { /* Cast away volatile qualifier, since we have lock. */ GC_thread gc_nvid = (GC_thread)gc_id; DWORD id = gc_nvid -> id; @@ -634,7 +652,7 @@ GC_API void GC_CALL GC_allow_register_threads(void) /* Check GC is initialized and the current thread is registered. */ GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0); -# if defined(GC_DLL) && !defined(PARALLEL_MARK) && !defined(THREAD_LOCAL_ALLOC) +# if !defined(GC_NO_DLLMAIN) && !defined(PARALLEL_MARK) /* GC_init_parallel() is not called from GC_init_inner(). */ parallel_initialized = TRUE; # endif @@ -706,6 +724,7 @@ DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE]; /* Assumes we do NOT hold the allocation lock. */ static GC_thread GC_lookup_pthread(pthread_t id) { +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); @@ -718,7 +737,9 @@ static GC_thread GC_lookup_pthread(pthread_t id) i++); if (i > my_max) return 0; return (GC_thread)(dll_thread_table + i); - } else { + } +#endif + { /* We first try the cache. If that fails, we use a very slow */ /* approach. */ int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ; @@ -748,6 +769,7 @@ static GC_thread GC_lookup_pthread(pthread_t id) void GC_push_thread_structures(void) { GC_ASSERT(I_HOLD_LOCK()); +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { /* Unlike the other threads implementations, the thread table here */ /* contains no pointers to the collectable heap. Thus we have */ @@ -762,7 +784,9 @@ void GC_push_thread_structures(void) (ptr_t)(&(dll_thread_table[i].status)+1)); } # endif - } else { + } else +#endif + /* else */ { GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads)); } # if defined(THREAD_LOCAL_ALLOC) @@ -773,6 +797,7 @@ void GC_push_thread_structures(void) } #if defined(MPROTECT_VDB) && !defined(MSWINCE) +# include "atomic_ops.h" extern volatile AO_TS_t GC_fault_handler_lock; /* from os_dep.c */ #endif @@ -828,8 +853,6 @@ STATIC void GC_suspend(GC_thread t) void GC_stop_world(void) { DWORD thread_id = GetCurrentThreadId(); - int i; - int my_max; if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()"); GC_ASSERT(I_HOLD_LOCK()); @@ -847,7 +870,10 @@ void GC_stop_world(void) # ifndef CYGWIN32 EnterCriticalSection(&GC_write_cs); # endif +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { + int i; + int my_max; /* Any threads being created during this loop will end up setting */ /* GC_attached_thread when they start. This will force marking to */ /* restart. */ @@ -861,7 +887,9 @@ void GC_stop_world(void) GC_suspend((GC_thread)t); } } - } else { + } else +#endif + /* else */ { GC_thread t; int i; @@ -1088,7 +1116,7 @@ void GC_push_all_stacks(void) # ifndef SMALL_CONFIG unsigned nthreads = 0; # endif - +#ifndef GC_NO_DLLMAIN if (GC_win32_dll_threads) { int i; LONG my_max = GC_get_max_thread_index(); @@ -1103,7 +1131,9 @@ void GC_push_all_stacks(void) if (t -> id == me) found_me = TRUE; } } - } else { + } else +#endif + /* else */ { GC_thread t; int i; @@ -1257,7 +1287,11 @@ void GC_get_next_stack(char *start, char *limit, #ifdef GC_PTHREADS STATIC void * GC_mark_thread(void * id) #else - STATIC unsigned __stdcall GC_mark_thread(void * id) +# ifdef MSWINCE + STATIC DWORD WINAPI GC_mark_thread(LPVOID id) +# else + STATIC unsigned __stdcall GC_mark_thread(void * id) +# endif #endif { word my_mark_no = 0; @@ -1418,19 +1452,37 @@ void GC_notify_all_marker(void) #else /* ! GC_PTHREADS */ +# ifndef MARK_THREAD_STACK_SIZE +# define MARK_THREAD_STACK_SIZE 0 /* default value */ +# endif + STATIC void start_mark_threads(void) { int i; - GC_uintptr_t handle; - unsigned thread_id; +# ifdef MSWINCE + HANDLE handle; + DWORD thread_id; +# else + GC_uintptr_t handle; + unsigned thread_id; +# endif for (i = 0; i < GC_markers - 1; ++i) { marker_last_stack_min[i] = ADDR_LIMIT; - handle = _beginthreadex(NULL /* security_attr */, 0 /* 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); +# ifdef MSWINCE + /* There is no _beginthreadex() in WinCE. */ + handle = CreateThread(NULL /* lpsa */, MARK_THREAD_STACK_SIZE, + GC_mark_thread, (LPVOID)(word)i, + 0 /* fdwCreate */, &thread_id); + if (!handle || handle == (HANDLE)-1L) + WARN("Marker thread creation failed\n", 0); +# 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); +# endif else { /* We may detach the thread (if handle is of HANDLE type) */ /* CloseHandle((HANDLE)handle); */ } @@ -1747,14 +1799,18 @@ GC_API void GC_CALL GC_endthreadex(unsigned retval) typedef struct { HINSTANCE hInstance; HINSTANCE hPrevInstance; - LPWSTR lpCmdLine; + GC_WINMAIN_WINCE_LPTSTR lpCmdLine; 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 + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPWSTR lpCmdLine, int nShowCmd) + GC_WINMAIN_WINCE_LPTSTR lpCmdLine, int nShowCmd) { DWORD exit_code = 1; @@ -1768,8 +1824,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, GC_init(); /* start the main thread */ - thread_h = GC_CreateThread( - NULL, 0, main_thread_start, &args, 0, &thread_id); + thread_h = GC_CreateThread(NULL /* lpsa */, WINCE_MAIN_STACK_SIZE, + main_thread_start, &args, 0 /* fdwCreate */, + &thread_id); if (thread_h != NULL) { @@ -1792,7 +1849,7 @@ DWORD WINAPI main_thread_start(LPVOID arg) args->lpCmdLine, args->nShowCmd); } -# else /* !MSWINCE */ +#endif /* MSWINCE */ /* Called by GC_init() - we hold the allocation lock. */ void GC_thr_init(void) { @@ -1813,7 +1870,7 @@ void GC_thr_init(void) { GC_get_stack_base(&sb); GC_ASSERT(sb_result == GC_SUCCESS); -# ifdef PARALLEL_MARK +# if defined(PARALLEL_MARK) && !defined(MSWINCE) /* Set GC_markers. */ { char * markers_string = GETENV("GC_MARKERS"); @@ -1854,7 +1911,7 @@ void GC_thr_init(void) { if (GC_markers <= 1 || GC_win32_dll_threads # ifndef GC_PTHREADS || GC_wnt == FALSE - || (hK32 = GetModuleHandleA("kernel32.dll")) == (HMODULE)0 + || (hK32 = GetModuleHandle(TEXT("kernel32.dll"))) == (HMODULE)0 || (signalObjectAndWait_func = (SignalObjectAndWait_type) GetProcAddress(hK32, "SignalObjectAndWait")) == 0 # endif @@ -1865,13 +1922,13 @@ void GC_thr_init(void) { } else { # ifndef GC_PTHREADS /* Initialize Win32 event objects for parallel marking. */ - mark_mutex_event = CreateEventA(NULL /* attrs */, + mark_mutex_event = CreateEvent(NULL /* attrs */, FALSE /* isManualReset */, FALSE /* initialState */, NULL /* name */); - builder_cv = CreateEventA(NULL /* attrs */, + builder_cv = CreateEvent(NULL /* attrs */, TRUE /* isManualReset */, FALSE /* initialState */, NULL /* name */); - mark_cv = CreateEventA(NULL /* attrs */, TRUE /* isManualReset */, + mark_cv = CreateEvent(NULL /* attrs */, TRUE /* isManualReset */, FALSE /* initialState */, NULL /* name */); if (mark_mutex_event == (HANDLE)0 || builder_cv == (HANDLE)0 || mark_cv == (HANDLE)0) @@ -2134,7 +2191,7 @@ int GC_pthread_detach(pthread_t thread) * the collector here seems dangerous, since DllMain is limited in what it * can do.) */ -#ifdef GC_DLL +#ifndef GC_NO_DLLMAIN /*ARGSUSED*/ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) { @@ -2203,10 +2260,9 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) } return TRUE; } -#endif /* GC_DLL */ -#endif /* !GC_PTHREADS */ +#endif /* !GC_NO_DLLMAIN */ -# endif /* !MSWINCE */ +#endif /* !GC_PTHREADS */ /* Perform all initializations, including those that */ /* may require allocation. */ |