[Gc] Addition of GC_allow_register_threads

Ivan Maidanski ivmai at mail.ru
Sat Nov 22 05:58:24 PST 2008


Hi!

At present it's impossible to correctly manually attach the first non-main thread (because GC_need_to_lock is false). So, I've added void GC_allow_register_threads() to API which must be called from an application's main thread to enable GC_register_my_thread() to do its work correctly (not necessary if we've already called a GC thread creation routine).

This patch also does:
- improve comment for GC_unregister_my_thread() (only an explicitly registered thread is allowed to unregister);
- eliminate nested locking in GC_init_parallel() (Win32/Cygwin);
- optimize locking in GC_register_my_thread() and remove now unused GC_lookup_thread() (Win32/Cygwin).

Bye.

-------------- next part --------------
diff -ru bdwgc/include/gc.h updated/bdwgc/include/gc.h
--- bdwgc/include/gc.h	2008-11-20 16:58:00.000000000 +0300
+++ updated/bdwgc/include/gc.h	2008-11-22 16:34:42.000000000 +0300
@@ -902,12 +902,21 @@
 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		*/
@@ -923,7 +932,9 @@
 #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	*/
+/* Unregister the current thread.  Only an explicity registered thread	*/
+/* (i.e. for which GC_register_my_thread() returns GC_SUCCESS) is	*/
+/* allowed 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 	*/
diff -ru bdwgc/pthread_support.c updated/bdwgc/pthread_support.c
--- bdwgc/pthread_support.c	2008-11-13 14:48:11.000000000 +0300
+++ updated/bdwgc/pthread_support.c	2008-11-22 13:21:26.000000000 +0300
@@ -1030,11 +1030,22 @@
     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) {
diff -ru bdwgc/win32_threads.c updated/bdwgc/win32_threads.c
--- bdwgc/win32_threads.c	2008-11-13 16:48:13.000000000 +0300
+++ updated/bdwgc/win32_threads.c	2008-11-22 15:03:44.000000000 +0300
@@ -496,23 +496,6 @@
   }
 }
 
-/* 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;
-  }
-}
-
 /* If a thread has been joined, but we have not yet		*/
 /* been notified, then there may be more than one thread 	*/
 /* in the table with the same win32 id.				*/
@@ -596,16 +579,28 @@
   }
 }
 
+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);
+
+  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 (0 == GC_lookup_thread(t)) {
-    /* We lock here, since we want to wait for an ongoing GC.	*/
-    LOCK();
+  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)) {
     GC_register_my_thread_inner(sb, t);
     UNLOCK();
     return GC_SUCCESS;
   } else {
+    UNLOCK();
     return GC_DUPLICATE;
   }
 }
@@ -1836,7 +1831,8 @@
       }
 #   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.  */
@@ -2176,7 +2172,7 @@
     /* 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
 }


More information about the Gc mailing list