+2009-06-12 Hans Boehm <Hans.Boehm@hp.com> (Really Ivan Maidanski)
+
+ diff97 (resembling diff43, diff51, diff67, diff76, diff83 partly)
+ * pthread_support.c (GC_inner_start_routine): Don't release the
+ GC lock between GC_register_my_thread_inner() and
+ GC_init_thread_local() calls (post the "registered" even after
+ calling GC_init_thread_local()).
+ * win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
+ Use GC_lookup_thread_inner() instead of GC_lookup_thread() and
+ acquire the GC lock only once.
+ * win32_threads.c (GC_thr_init): Call GC_register_my_thread_inner()
+ directly instead of GC_register_my_thread() since I_HOLD_LOCK
+ and our (main) thread is not registered yet (add assertion for it).
+ * win32_threads.c (GC_init_parallel): Call GC_lookup_thread_inner()
+ directly instead of GC_lookup_thread() (since I_HOLD_LOCK).
+ * win32_threads.c (GC_lookup_thread): Remove unused function.
+ * win32_threads.c: Remove "#error GC_DLL untested with Cygwin".
+ * win32_threads.c (GC_win32_dll_threads): Define as FALSE macro
+ also if THREAD_LOCAL_ALLOC or GC_PTHREADS.
+ * win32_threads.c (GC_use_DllMain): Call ABORT also if GC_PTHREADS
+ (for Cygwin).
+ * win32_threads.c (GC_push_stack_for): Add parentheses around "&&"
+ (inside GC_ASSERT) to prevent compiler warning.
+ * win32_threads.c (GC_push_all_stacks): Remove FIXME for
+ PARALLEL_MARK.
+ * win32_threads.c (MAX_MARKERS, GC_markers): Move the definitions
+ to a place before GC_get_next_stack().
+ * win32_threads.c (marker_sp, marker_bsp): New static arrays (same
+ as in pthread_support.c).
+ * win32_threads.c (marker_last_stack_min): New static arrays (the
+ same semantics as for last_stack_min of GC_Thread_Rep).
+ * win32_threads.c (GC_get_next_stack): Handle marker threads.
+ * win32_threads.c (GC_mark_thread): Save the current stack pointer
+ to marker_[b]sp.
+ * win32_threads.c (start_mark_threads): Initialize
+ marker_last_stack_min elements (to "unset" value).
+
2009-06-12 Hans Boehm <Hans.Boehm@hp.com> (Really Ivan Maidanski)
(diff96_cvs, partly from diff45 and diff75)
#ifdef GC_PTHREADS
# include <errno.h>
-/* GC_DLL should not normally be defined, especially since we often do turn */
-/* on THREAD_LOCAL_ALLOC, which is currently incompatible. */
-/* 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. */
-#ifdef GC_DLL
-# error GC_DLL untested with Cygwin
-#endif
-
/* Cygwin-specific forward decls */
# undef pthread_create
# undef pthread_sigmask
#endif
-#if defined(GC_DLL) && !defined(MSWINCE)
+/* DllMain-based thread registration is currently incompatible */
+/* with thread-local allocation, pthreads and WinCE. */
+#if defined(GC_DLL) && !defined(MSWINCE) \
+ && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
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 */
void GC_init_parallel(void);
-#ifdef GC_DLL
+/* 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)
/* Turn on GC_win32_dll_threads */
GC_API void GC_CALL GC_use_DllMain(void)
{
}
}
-/* A version of the above that acquires the lock if necessary. Note */
-/* that the identically named function for pthreads is different, and */
-/* just assumes we hold the lock. */
-/* Also used (for assertion checking only) from thread_local_alloc.c. */
-static GC_thread GC_lookup_thread(DWORD thread_id)
-{
- if (GC_win32_dll_threads) {
- return GC_lookup_thread_inner(thread_id);
- } else {
- GC_thread result;
- LOCK();
- result = GC_lookup_thread_inner(thread_id);
- UNLOCK();
- return result;
- }
-}
-
/* Make sure thread descriptor t is not protected by the VDB */
/* implementation. */
/* Used to prevent write faults when the world is (partially) stopped, */
GC_API int GC_CALL GC_register_my_thread(struct GC_stack_base *sb) {
DWORD t = GetCurrentThreadId();
- if (0 == GC_lookup_thread(t)) {
- /* We lock here, since we want to wait for an ongoing GC. */
- LOCK();
+ /* We lock here, since we want to wait for an ongoing GC. */
+ LOCK();
+ if (0 == GC_lookup_thread_inner(t)) {
GC_register_my_thread_inner(sb, t);
UNLOCK();
return GC_SUCCESS;
} else {
+ UNLOCK();
return GC_DUPLICATE;
}
}
{
DWORD t = GetCurrentThreadId();
-# if defined(THREAD_LOCAL_ALLOC)
- LOCK();
- {
- 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? */
+# if defined(THREAD_LOCAL_ALLOC)
+ /* Can't happen: see GC_use_DllMain(). */
+# endif
+ /* FIXME: Should we just ignore this? */
GC_delete_thread(t);
} else {
LOCK();
+# if defined(THREAD_LOCAL_ALLOC)
+ {
+ GC_thread me = GC_lookup_thread_inner(t);
+ GC_destroy_thread_local(&(me->tlfs));
+ }
+# endif
GC_delete_thread(t);
UNLOCK();
}
}
}
GC_ASSERT(stack_min == GC_get_stack_min(thread -> stack_base)
- || sp >= stack_min && stack_min < thread -> stack_base
- && stack_min > GC_get_stack_min(thread -> stack_base));
+ || (sp >= stack_min && stack_min < thread -> stack_base
+ && stack_min > GC_get_stack_min(thread -> stack_base)));
if (sp >= stack_min && sp < thread->stack_base) {
# ifdef DEBUG_THREADS
if (GC_print_stats == VERBOSE) {
GC_log_printf("Pushed %d thread stacks%s\n", nthreads,
GC_win32_dll_threads ? " based on DllMain thread tracking" : "");
-# ifdef PARALLEL_MARK
- /* FIXME: Should we scan marker threads here too? */
-# endif
}
# endif
if (!found_me && !GC_in_thread_creation)
ABORT("Collecting from unknown thread.");
}
+#ifdef PARALLEL_MARK
+
+# ifndef MAX_MARKERS
+# define MAX_MARKERS 16
+# endif
+
+ extern long GC_markers; /* Number of mark threads we would */
+ /* like to have. Includes the */
+ /* initiating thread. */
+
+ STATIC ptr_t marker_sp[MAX_MARKERS - 1]; /* The cold end of the stack */
+ /* for markers. */
+# ifdef IA64
+ STATIC ptr_t marker_bsp[MAX_MARKERS - 1];
+# endif
+
+ STATIC ptr_t marker_last_stack_min[MAX_MARKERS - 1];
+ /* Last known minimum (hottest) address */
+ /* in stack (or ADDR_LIMIT if unset) */
+ /* for markers. */
+
+#endif
+
/* Find stack with the lowest address which overlaps the */
/* interval [start, limit). */
/* Return stack bounds in *lo and *hi. If no such stack */
}
}
}
+# ifdef PARALLEL_MARK
+ for (i = 0; i < GC_markers - 1; ++i) {
+ ptr_t s = marker_sp[i];
+# ifdef IA64
+ /* FIXME: not implemented */
+# endif
+ if (s > start && s < current_min) {
+ GC_ASSERT(marker_last_stack_min[i] != NULL);
+ plast_stack_min = &marker_last_stack_min[i];
+ current_min = s;
+ thread = NULL; /* Not a thread's hash table entry. */
+ }
+ }
+# endif
}
*hi = current_min;
#ifdef PARALLEL_MARK
-# ifndef MAX_MARKERS
-# define MAX_MARKERS 16
-# endif
-
/* GC_mark_thread() is the same as in pthread_support.c */
- /* except for unused marker_[b]sp. */
#ifdef GC_PTHREADS
STATIC void * GC_mark_thread(void * id)
#else
{
word my_mark_no = 0;
+ marker_sp[(word)id] = GC_approx_sp();
+# ifdef IA64
+ marker_bsp[(word)id] = GC_save_regs_in_stack();
+# endif
+
if ((word)id == (word)-1) return 0; /* to make compiler happy */
for (;; ++my_mark_no) {
}
}
-extern long GC_markers; /* Number of mark threads we would */
- /* like to have. Includes the */
- /* initiating thread. */
-
#ifdef GC_ASSERTIONS
unsigned long GC_mark_lock_holder = NO_THREAD;
#endif
ABORT("pthread_attr_setdetachstate failed");
for (i = 0; i < GC_markers - 1; ++i) {
+ 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",
unsigned thread_id;
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);
}
# endif /* PARALLEL_MARK */
- GC_register_my_thread(&sb);
+ GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
+ GC_register_my_thread_inner(&sb, GC_main_thread);
# ifdef PARALLEL_MARK
/* If we are using a parallel marker, actually start helper threads. */
/* Initialize thread local free lists if used. */
# if defined(THREAD_LOCAL_ALLOC)
LOCK();
- GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs));
+ GC_init_thread_local(&GC_lookup_thread_inner(GetCurrentThreadId())->tlfs);
UNLOCK();
# endif
}