/* Allocation lock declarations. */
#if !defined(USE_PTHREAD_LOCKS)
- /* GC_allocate_ml declaration in gc_locks.h suffices. */
+# if defined(GC_DLL)
+ __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
+# else
+ CRITICAL_SECTION GC_allocate_ml;
+# endif
DWORD GC_lock_holder = NO_THREAD;
/* Thread id for current holder of allocation lock */
#else
# undef ExitThread
# undef _beginthreadex
# undef _endthreadex
+# include <process.h> /* For _beginthreadex, _endthreadex */
#endif
};
typedef struct GC_Thread_Rep * GC_thread;
-
+typedef volatile struct GC_Thread_Rep * GC_vthread;
/*
* We assumed that volatile ==> memory ordering, at least among
/* This is a chained hash table, with much of the code borrowed */
/* From the Posix implementation. */
# define THREAD_TABLE_SZ 256 /* Must be power of 2 */
- volatile GC_thread GC_threads[THREAD_TABLE_SZ];
+ GC_thread GC_threads[THREAD_TABLE_SZ];
/* Add a thread to GC_threads. We assume it wasn't already there. */
GC_ASSERT(!GC_win32_dll_threads);
result = (struct GC_Thread_Rep *)
GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- GC_ASSERT(result -> flags == 0);
+# ifdef CYGWIN32
+ GC_ASSERT(result -> flags == 0);
+# endif
}
if (result == 0) return(0);
/* result -> id = id; Done by caller. */
result -> next = GC_threads[hv];
GC_threads[hv] = result;
- GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
+# ifdef CYGWIN32
+ GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
+# endif
return(result);
}
extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
+#if defined(GWW_VDB) && defined(MPROTECT_VDB)
+ extern GC_bool GC_gww_dirty_init(void);
+ /* Defined in os_dep.c. Returns TRUE if GetWriteWatch is available. */
+ /* may be called repeatedly. */
+#endif
+
/*
* This may be called from DllMain, and hence operates under unusual
* constraints. In particular, it must be lock-free if GC_win32_dll_threads
static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
DWORD thread_id)
{
- volatile struct GC_Thread_Rep * me;
+ GC_vthread me;
/* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
# if defined(MPROTECT_VDB)
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# if defined(GWW_VDB)
+ if (GC_incremental && !GC_gww_dirty_init())
+ SetUnhandledExceptionFilter(GC_write_fault_handler);
+# else
+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# endif
# endif
if (GC_win32_dll_threads || !client_has_run) {
/* GC_win32_dll_threads is set. */
/* If GC_win32_dll_threads is set it should be called from the */
/* thread being deleted. */
-void GC_delete_gc_thread(GC_thread gc_id)
+void GC_delete_gc_thread(GC_vthread gc_id)
{
if (GC_win32_dll_threads) {
/* This is intended to be lock-free. */
/* It is either called synchronously from the thread being deleted, */
/* or by the joining thread. */
+ /* In this branch asynchronosu changes to *gc_id are possible. */
CloseHandle(gc_id->handle);
- /* cast away volatile qualifier */
gc_id -> stack_base = 0;
gc_id -> id = 0;
# ifdef CYGWIN32
# endif /* CYGWIN32 */
AO_store_release(&(gc_id->in_use), FALSE);
} else {
- DWORD id = gc_id -> id;
+ /* Cast away volatile qualifier, since we have lock. */
+ GC_thread gc_nvid = (GC_thread)gc_id;
+ DWORD id = gc_nvid -> id;
int hv = ((word)id) % THREAD_TABLE_SZ;
register GC_thread p = GC_threads[hv];
register GC_thread prev = 0;
GC_ASSERT(I_HOLD_LOCK());
- while (p != gc_id) {
+ while (p != gc_nvid) {
prev = p;
p = p -> next;
}
int GC_unregister_my_thread(void)
{
- if (GC_win32_dll_threads) {
- /* Should we just ignore this? */
- GC_delete_thread(GetCurrentThreadId());
- } else {
- LOCK();
- GC_delete_thread(GetCurrentThreadId());
- UNLOCK();
- }
+ DWORD t = GetCurrentThreadId();
+
# if defined(THREAD_LOCAL_ALLOC)
LOCK();
{
- GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
+ GC_thread me = GC_lookup_thread_inner(t);
GC_destroy_thread_local(&(me->tlfs));
}
UNLOCK();
# endif
+ if (GC_win32_dll_threads) {
+ /* Should we just ignore this? */
+ GC_delete_thread(t);
+ } else {
+ LOCK();
+ GC_delete_thread(t);
+ UNLOCK();
+ }
return GC_SUCCESS;
}
/* in the thread registration code until GC_please_stop becomes */
/* false. This is not ideal, but hopefully correct. */
for (i = 0; i <= GC_get_max_thread_index(); i++) {
- volatile struct GC_Thread_Rep * t = dll_thread_table + i;
+ GC_vthread t = dll_thread_table + i;
if (t -> stack_base != 0
&& t -> id != thread_id) {
GC_suspend((GC_thread)t);
#ifndef __GNUC__
} __finally {
#endif /* __GNUC__ */
-# if defined(THREAD_LOCAL_ALLOC)
- LOCK();
- GC_destroy_thread_local(&(me->tlfs));
- UNLOCK();
-# endif
+ GC_unregister_my_thread();
GC_free(args);
- GC_delete_thread(GetCurrentThreadId());
#ifndef __GNUC__
}
#endif /* __GNUC__ */