+2009-08-01 Hans Boehm <Hans.Boehm@hp.com> (Really Ivan Maidanski)
+ diff100_cvs (diff51 and diff55, partly)
+
+ * pthread_support.c (GC_allow_register_threads): New API function.
+ * win32_threads.c (GC_allow_register_threads): Ditto.
+ * include/gc.h (GC_allow_register_threads): New API prototype.
+ * include/gc.h (GC_register_my_thread, GC_unregister_my_thread):
+ Update the comments.
+ * pthread_support.c (GC_register_my_thread): Check the collector
+ is in the multi-threaded mode.
+ * win32_threads.c (GC_register_my_thread): Ditto.
+
2009-07-10 Hans Boehm <Hans.Boehm@hp.com>
* finalize.c (GC_finalize_all): Always call GC_invoke_finalizers
GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn,
void *arg);
+/* Explicitly enable GC_register_my_thread() invocation. */
+/* Done implicitly if a GC thread-creation function is called (or */
+/* DllMain-based thread registration is enabled). Otherwise, it must */
+/* be called from the main (or any previously registered) thread */
+/* between the collector initialization and the first explicit */
+/* registering of a thread (it should be called as late as possible). */
+GC_API void GC_CALL GC_allow_register_threads(void);
+
/* Register the current thread, with the indicated stack base, as */
/* a new thread whose stack(s) should be traced by the GC. If it */
/* is not implicitly called by the GC, this must be called before a */
/* thread can allocate garbage collected memory, or assign pointers */
/* to the garbage collected heap. Once registered, a thread will be */
/* stopped during garbage collections. */
+/* This call must be previously enabled (see above). */
/* This should never be called from the main thread, where it is */
/* always done implicitly. This is normally done implicitly if GC_ */
/* functions are called to create the thread, e.g. by defining */
#define GC_UNIMPLEMENTED 3 /* Not yet implemented on this platform. */
GC_API int GC_CALL GC_register_my_thread(struct GC_stack_base *);
-/* Unregister the current thread. The thread may no longer allocate */
-/* garbage collected memory or manipulate pointers to the */
-/* garbage collected heap after making this call. */
+/* Unregister the current thread. Only an explicity registered thread */
+/* (i.e. for which GC_register_my_thread() returns GC_SUCCESS) is */
+/* allowed (and required) to call this function. The thread may no */
+/* longer allocate garbage collected memory or manipulate pointers to */
+/* the garbage collected heap after making this call. */
/* 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 */
return me;
}
+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(pthread_self()) != 0);
+
+ GC_need_to_lock = TRUE; /* We are multi-threaded now. */
+}
+
GC_API int GC_CALL GC_register_my_thread(struct GC_stack_base *sb)
{
pthread_t my_pthread = pthread_self();
GC_thread me;
+ if (GC_need_to_lock == FALSE)
+ ABORT("Threads explicit registering is not previously enabled");
+
LOCK();
me = GC_lookup_thread(my_pthread);
if (0 == me) {
}
}
+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)
+ /* GC_init_parallel() is not called from GC_init_inner(). */
+ parallel_initialized = TRUE;
+# endif
+ GC_need_to_lock = TRUE; /* We are multi-threaded now. */
+}
+
GC_API int GC_CALL GC_register_my_thread(struct GC_stack_base *sb) {
DWORD t = GetCurrentThreadId();
+ if (GC_need_to_lock == FALSE)
+ ABORT("Threads explicit registering is not previously enabled");
+
/* We lock here, since we want to wait for an ongoing GC. */
LOCK();
if (0 == GC_lookup_thread_inner(t)) {