2009-12-18 Ivan Maidanski <ivmai@mail.ru> (with input from
authorivmai <ivmai>
Fri, 18 Dec 2009 12:09:55 +0000 (12:09 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 17:06:52 +0000 (21:06 +0400)
                                    Jean-Claude Beaudoin)

* include/gc.h (GC_unregister_my_thread): Fix a typo; update the
comment.
* pthread_support.c (GC_delete_thread): Allow to delete the main
thread (don't call GC_INTERNAL_FREE for it); update the comment.
* win32_threads.c (GC_delete_thread): Ditto.
* pthread_support.c (GC_unregister_my_thread): Add an assertion
for FINISHED flag is unset.
* tests/test.c (check_heap_stats): Test the main thread
unregistering (only if THREADS).
* win32_threads.c (GC_register_my_thread_inner): Set flags to
DETACHED (only if GC_PTHREADS).
* win32_threads.c (GC_unregister_my_thread): Add FIXME (for
GC_wait_for_gc_completion).
* win32_threads.c (GC_pthread_start_inner): Clear flags detached
state if needed; set pthread_id and flags while holding the lock.

ChangeLog
include/gc.h
pthread_support.c
tests/test.c
win32_threads.c

index acc8578..8d45463 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,28 @@
-2009-12-07  Ivan Maidanski <ivmai@mail.ru> (with input from Andy Wingo)
+2009-12-18  Ivan Maidanski <ivmai@mail.ru> (with input from
+                                           Jean-Claude Beaudoin)
+
+       * include/gc.h (GC_unregister_my_thread): Fix a typo; update the
+       comment.
+       * pthread_support.c (GC_delete_thread): Allow to delete the main
+       thread (don't call GC_INTERNAL_FREE for it); update the comment.
+       * win32_threads.c (GC_delete_thread): Ditto.
+       * pthread_support.c (GC_unregister_my_thread): Add an assertion
+       for FINISHED flag is unset.
+       * tests/test.c (check_heap_stats): Test the main thread
+       unregistering (only if THREADS).
+       * win32_threads.c (GC_register_my_thread_inner): Set flags to
+       DETACHED (only if GC_PTHREADS).
+       * win32_threads.c (GC_unregister_my_thread): Add FIXME (for
+       GC_wait_for_gc_completion).
+       * win32_threads.c (GC_pthread_start_inner): Clear flags detached
+       state if needed; set pthread_id and flags while holding the lock.
+
+2009-12-17  Ivan Maidanski <ivmai@mail.ru> (with input from Andy Wingo)
 
        * include/private/gc_priv.h (SIG_SUSPEND): Don't define for
        OpenBSD and Darwin.
 
-2009-12-07  Ivan Maidanski <ivmai@mail.ru>
+2009-12-17  Ivan Maidanski <ivmai@mail.ru>
 
        * include/gc.h: Recognize _M_X64 (as an alias for _AMD64_).
 
index 03511c1..562ff19 100644 (file)
@@ -1067,13 +1067,14 @@ GC_API void GC_CALL GC_allow_register_threads(void);
 /* libraries.                                                           */
 GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *);
 
-/* Unregister the current thread.  Only an explicity registered thread  */
+/* Unregister the current thread.  Only an explicitly 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     */
+/* allowed (and required) to call this function.  (As a special         */
+/* exception, it is also allowed to once unregister the main thread.)   */
+/* 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        */
 /* 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).   */
index bb95e19..fc76714 100644 (file)
@@ -397,6 +397,7 @@ STATIC GC_thread GC_new_thread(pthread_t id)
 
 /* Delete a thread from GC_threads.  We assume it is there.     */
 /* (The code intentionally traps if it wasn't.)                 */
+/* It is safe to delete the main thread.                        */
 STATIC void GC_delete_thread(pthread_t id)
 {
     int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
@@ -413,10 +414,12 @@ STATIC void GC_delete_thread(pthread_t id)
     } else {
         prev -> next = p -> next;
     }
-#   ifdef GC_DARWIN_THREADS
+    if (p != &first_thread) {
+#     ifdef GC_DARWIN_THREADS
         mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
-#   endif
-    GC_INTERNAL_FREE(p);
+#     endif
+      GC_INTERNAL_FREE(p);
+    }
 }
 
 /* If a thread has been joined, but we have not yet             */
@@ -1042,6 +1045,7 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
     /* complete before we remove this thread.                   */
     GC_wait_for_gc_completion(FALSE);
     me = GC_lookup_thread(pthread_self());
+    GC_ASSERT(!(me -> flags & FINISHED));
 #   if defined(THREAD_LOCAL_ALLOC)
       GC_destroy_thread_local(&(me->tlfs));
 #   endif
index c78c119..ad07c78 100644 (file)
@@ -1340,6 +1340,9 @@ void check_heap_stats(void)
         (void)GC_printf("Unexpected heap growth - collector may be broken\n");
         FAIL;
     }
+#   ifdef THREADS
+      GC_unregister_my_thread(); /* just to check it works (for main) */
+#   endif
     (void)GC_printf("Collector appears to work\n");
 }
 
index 82d1d53..3b0e818 100644 (file)
@@ -442,6 +442,7 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
 # ifdef GC_PTHREADS
     /* me can be NULL -> segfault */
     me -> pthread_id = pthread_self();
+    me -> flags = DETACHED; /* cleared in GC_pthread_start_inner if needed */
 # endif
 # ifndef MSWINCE
     /* GetCurrentThread() returns a pseudohandle (a const value).       */
@@ -652,11 +653,11 @@ STATIC void GC_delete_gc_thread(GC_vthread gc_id)
 }
 
 /* Delete a thread from GC_threads.  We assume it is there.     */
-/* (The code intentionally traps if it wasn't.)                 */
-/* Assumes we hold the allocation lock unless                   */
-/* GC_win32_dll_threads is set.                                 */
-/* If GC_win32_dll_threads is set it should be called from the  */
-/* thread being deleted.                                        */
+/* (The code intentionally traps if it wasn't.)  Assumes we     */
+/* hold the allocation lock unless GC_win32_dll_threads is set. */
+/* If GC_win32_dll_threads is set then it should be called from */
+/* the thread being deleted.  It is also safe to delete the     */
+/* main thread (unless GC_win32_dll_threads).                   */
 STATIC void GC_delete_thread(DWORD id)
 {
   if (GC_win32_dll_threads) {
@@ -685,7 +686,9 @@ STATIC void GC_delete_thread(DWORD id)
     } else {
       prev -> tm.next = p -> tm.next;
     }
-    GC_INTERNAL_FREE(p);
+    if (p != &first_thread) {
+      GC_INTERNAL_FREE(p);
+    }
   }
 }
 
@@ -723,7 +726,7 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
 GC_API int GC_CALL GC_unregister_my_thread(void)
 {
   DWORD t = GetCurrentThreadId();
-
+  /* FIXME: is GC_wait_for_gc_completion(FALSE) needed here? */
   if (GC_win32_dll_threads) {
 #   if defined(THREAD_LOCAL_ALLOC)
       /* Can't happen: see GC_use_DllMain(). */
@@ -2433,12 +2436,12 @@ GC_INNER void GC_thr_init(void)
     /* we don't need to hold the allocation lock during pthread_create. */
     me = GC_register_my_thread_inner(sb, thread_id);
     SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
+    me -> pthread_id = pthread_id;
+    if (!si->detached) me -> flags &= ~DETACHED;
     UNLOCK();
 
     start = si -> start_routine;
     start_arg = si -> arg;
-    if (si-> detached) me -> flags |= DETACHED;
-    me -> pthread_id = pthread_id;
 
     GC_free(si); /* was allocated uncollectable */