]> granicus.if.org Git - gc/commitdiff
2010-10-22 Ivan Maidanski <ivmai@mail.ru>
authorivmai <ivmai>
Fri, 22 Oct 2010 05:47:47 +0000 (05:47 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 17:06:55 +0000 (21:06 +0400)
* CMakeLists.txt: Check enable_parallel_mark on Darwin.
* configure.ac: Ditto.
* darwin_stop_world.c (DARWIN_SUSPEND_GC_THREADS,
DARWIN_QUERY_TASK_THREADS): Rename to GC_NO_THREADS_DISCOVERY and
GC_DISCOVER_TASK_THREADS, respectively.
* os_dep.c (DARWIN_SUSPEND_GC_THREADS): Ditto.
* pthread_support.c (DARWIN_SUSPEND_GC_THREADS): Ditto.
* darwin_stop_world.c (DARWIN_QUERY_TASK_THREADS): Don't define
(and remove FIXME).
* darwin_stop_world.c (GC_use_threads_discovery): Add GC_API;
comment; remove FIXME.
* win32_threads.c (GC_NO_DLLMAIN): Rename to
GC_NO_THREADS_DISCOVERY.
* tests/test.c (GC_NO_DLLMAIN): Ditto.
* doc/README.macros (GC_NO_DLLMAIN): Ditto.
* doc/README.win32 (GC_NO_DLLMAIN): Ditto.
* doc/README.macros (GC_NO_THREADS_DISCOVERY): Update the comment.
* win32_threads.c (GC_win32_dll_threads): Define as macro to true
if GC_DISCOVER_TASK_THREADS (and not GC_NO_THREADS_DISCOVERY);
update the comment.
* win32_threads.c (GC_use_DllMain): Rename to
GC_use_threads_discovery; do not set GC_win32_dll_threads if
GC_DISCOVER_TASK_THREADS.
* win32_threads.c (GC_started_thread_while_stopped,
GC_lookup_thread_inner, UNPROTECT_THREAD, GC_lookup_pthread,
GC_thr_init, GC_pthread_create, DllMain): Rewrite some expressions
which use GC_win32_dll_threads to minimize the possibility of
an "unreachable code" compiler warning when GC_win32_dll_threads
is defined as a macro.
* win32_threads.c (GC_unregister_my_thread): Don't call
GC_delete_thread() if GC_win32_dll_threads and THREAD_LOCAL_ALLOC
(since can't happen); use "t" local variable only if not
GC_win32_dll_threads.
* win32_threads.c (GC_register_my_thread_inner): Reformat the
comment.
* doc/README.macros (GC_DISCOVER_TASK_THREADS): Document.
* include/gc.h (GC_use_DllMain): Rename to
GC_use_threads_discovery but keep old name as a macro definition.
* include/gc.h (GC_use_threads_discovery): Declare also for
Darwin; update the comment.
* tests/test.c (main): Call GC_use_threads_discovery for Darwin
(to test the mode if possible).
* configure: Regenerate.

12 files changed:
CMakeLists.txt
ChangeLog
configure
configure.ac
darwin_stop_world.c
doc/README.macros
doc/README.win32
include/gc.h
os_dep.c
pthread_support.c
tests/test.c
win32_threads.c

index ae82e03d4da88b58aafe270620c4039774df1cd8..2f775d49ebb77e5af59f19a18eff341e50af1354 100644 (file)
@@ -167,10 +167,9 @@ IF(CMAKE_USE_PTHREADS_INIT)
                 ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
                 MESSAGE("Explicit GC_INIT() calls may be required.")
                 SET(SRC ${SRC} darwin_stop_world.c)
-                # Parallel-mark is currently unreliable on Darwin; ignore request
-                #IF (${enable_parallel_mark})
-                #       ADD_DEFINITIONS("-DPARALLEL_MARK")
-                #ENDIF()
+                IF (${enable_parallel_mark})
+                       ADD_DEFINITIONS("-DPARALLEL_MARK")
+                ENDIF()
                 #TODO
                 #darwin_threads=true
         ENDIF()
index 4cb76a03cba7960a90caeeb78d905866ee6d3200..2dbff97882f80ec7ce894e2e4376323762a5444f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+2010-10-22  Ivan Maidanski <ivmai@mail.ru>
+
+       * CMakeLists.txt: Check enable_parallel_mark on Darwin.
+       * configure.ac: Ditto.
+       * darwin_stop_world.c (DARWIN_SUSPEND_GC_THREADS,
+       DARWIN_QUERY_TASK_THREADS): Rename to GC_NO_THREADS_DISCOVERY and
+       GC_DISCOVER_TASK_THREADS, respectively.
+       * os_dep.c (DARWIN_SUSPEND_GC_THREADS): Ditto.
+       * pthread_support.c (DARWIN_SUSPEND_GC_THREADS): Ditto.
+       * darwin_stop_world.c (DARWIN_QUERY_TASK_THREADS): Don't define
+       (and remove FIXME).
+       * darwin_stop_world.c (GC_use_threads_discovery): Add GC_API;
+       comment; remove FIXME.
+       * win32_threads.c (GC_NO_DLLMAIN): Rename to
+       GC_NO_THREADS_DISCOVERY.
+       * tests/test.c (GC_NO_DLLMAIN): Ditto.
+       * doc/README.macros (GC_NO_DLLMAIN): Ditto.
+       * doc/README.win32 (GC_NO_DLLMAIN): Ditto.
+       * doc/README.macros (GC_NO_THREADS_DISCOVERY): Update the comment.
+       * win32_threads.c (GC_win32_dll_threads): Define as macro to true
+       if GC_DISCOVER_TASK_THREADS (and not GC_NO_THREADS_DISCOVERY);
+       update the comment.
+       * win32_threads.c (GC_use_DllMain): Rename to
+       GC_use_threads_discovery; do not set GC_win32_dll_threads if
+       GC_DISCOVER_TASK_THREADS.
+       * win32_threads.c (GC_started_thread_while_stopped,
+       GC_lookup_thread_inner, UNPROTECT_THREAD, GC_lookup_pthread,
+       GC_thr_init, GC_pthread_create, DllMain): Rewrite some expressions
+       which use GC_win32_dll_threads to minimize the possibility of
+       an "unreachable code" compiler warning when GC_win32_dll_threads
+       is defined as a macro.
+       * win32_threads.c (GC_unregister_my_thread): Don't call
+       GC_delete_thread() if GC_win32_dll_threads and THREAD_LOCAL_ALLOC
+       (since can't happen); use "t" local variable only if not
+       GC_win32_dll_threads.
+       * win32_threads.c (GC_register_my_thread_inner): Reformat the
+       comment.
+       * doc/README.macros (GC_DISCOVER_TASK_THREADS): Document.
+       * include/gc.h (GC_use_DllMain): Rename to
+       GC_use_threads_discovery but keep old name as a macro definition.
+       * include/gc.h (GC_use_threads_discovery): Declare also for
+       Darwin; update the comment.
+       * tests/test.c (main): Call GC_use_threads_discovery for Darwin
+       (to test the mode if possible).
+       * configure: Regenerate.
+
 2010-10-16  Ivan Maidanski <ivmai@mail.ru>
 
        * darwin_stop_world.c (DARWIN_SUSPEND_GC_THREADS,
index c3fad5d22af255ced0f87e8ab0fdeefe28e6f90d..b3c4c5443c17a260a7571b0694cb64f1a210e348 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 1.61 .
+# From configure.ac Revision: 1.62 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.67 for gc 7.2alpha5.
 #
@@ -5145,10 +5145,11 @@ $as_echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
 
         { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
 $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
-        # Parallel-mark is currently unreliable on Darwin; ignore request
-        # if test "${enable_parallel_mark}" = yes; then
-        #   AC_DEFINE(PARALLEL_MARK)
-        # fi
+        # Parallel-mark is not well-tested on Darwin
+        if test "${enable_parallel_mark}" = yes; then
+          $as_echo "#define PARALLEL_MARK 1" >>confdefs.h
+
+        fi
         darwin_threads=true
         ;;
      *-*-osf*)
@@ -5162,7 +5163,7 @@ $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
           { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
 $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
           # May want to enable it in other cases, too.
-          # Measurements havent yet been done.
+          # Measurements have not yet been done.
         fi
         INCLUDES="$INCLUDES -pthread"
         THREADDLLIBS="-lpthread -lrt"
index c98ba41f324940f1718224c9fa545612dafd6514..748499dd6744a510cee60cd136e3db728782ecf7 100644 (file)
@@ -23,7 +23,7 @@ AC_CONFIG_SRCDIR(gcj_mlc.c)
 AC_CONFIG_MACRO_DIR([m4])
 AC_CANONICAL_TARGET
 AC_PREREQ(2.53)
-AC_REVISION($Revision: 1.62 $)
+AC_REVISION($Revision: 1.63 $)
 GC_SET_VERSION
 AM_INIT_AUTOMAKE([foreign dist-bzip2 nostdinc])
 AM_CONFIG_HEADER([include/private/config.h])
@@ -204,10 +204,10 @@ case "$THREADS" in
         AC_DEFINE(GC_DARWIN_THREADS)
         AC_DEFINE(THREAD_LOCAL_ALLOC)
         AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
-        # Parallel-mark is currently unreliable on Darwin; ignore request
-        if test "${enable_parallel_mark}" = yes; then
-          AC_DEFINE(PARALLEL_MARK)
-        fi
+        # Parallel-mark is not well-tested on Darwin
+        if test "${enable_parallel_mark}" = yes; then
+          AC_DEFINE(PARALLEL_MARK)
+        fi
         darwin_threads=true
         ;;
      *-*-osf*)
@@ -217,7 +217,7 @@ case "$THREADS" in
           AC_DEFINE(THREAD_LOCAL_ALLOC)
           AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
           # May want to enable it in other cases, too.
-          # Measurements havent yet been done.
+          # Measurements have not yet been done.
         fi
         INCLUDES="$INCLUDES -pthread"
         THREADDLLIBS="-lpthread -lrt"
index 3e14b63587aaf668440e0655eeaf2c772b0d9c36..5f152688ee9b69244abec0ca3514733c36755ebe 100644 (file)
@@ -87,26 +87,26 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
 
 #endif /* !DARWIN_DONT_PARSE_STACK */
 
-#define DARWIN_QUERY_TASK_THREADS 1 /* FIXME: Remove this. */
-
 /* GC_query_task_threads controls whether to obtain the list of */
 /* the threads from the kernel or to use GC_threads table.      */
-#ifdef DARWIN_SUSPEND_GC_THREADS
+#ifdef GC_NO_THREADS_DISCOVERY
 # define GC_query_task_threads FALSE
-#elif defined(DARWIN_QUERY_TASK_THREADS)
+#elif defined(GC_DISCOVER_TASK_THREADS)
 # define GC_query_task_threads TRUE
 #else
   STATIC GC_bool GC_query_task_threads = FALSE;
-#endif /* !DARWIN_SUSPEND_GC_THREADS */
+#endif /* !GC_NO_THREADS_DISCOVERY */
 
-/* FIXME: add GC_API and declare in gc.h; add comment; document macros */
-void GC_CALL GC_use_threads_discovery(void)
+/* Use implicit threads registration (all task threads excluding the GC */
+/* special ones are stoped and scanned).  Should be called before       */
+/* GC_INIT() (or, at least, before going multi-threaded).  Deprecated.  */
+GC_API void GC_CALL GC_use_threads_discovery(void)
 {
-# if defined(DARWIN_SUSPEND_GC_THREADS) || defined(DARWIN_DONT_PARSE_STACK)
+# if defined(GC_NO_THREADS_DISCOVERY) || defined(DARWIN_DONT_PARSE_STACK)
     ABORT("Darwin task-threads-based stop and push unsupported");
 # else
     GC_ASSERT(!GC_need_to_lock);
-#   ifndef DARWIN_QUERY_TASK_THREADS
+#   ifndef GC_DISCOVER_TASK_THREADS
       GC_query_task_threads = TRUE;
 #   endif
     GC_init_parallel(); /* just to be consistent with Win32 one */
@@ -326,7 +326,7 @@ GC_INNER void GC_push_all_stacks(void)
   GC_total_stacksize = total_size;
 }
 
-#ifndef DARWIN_SUSPEND_GC_THREADS
+#ifndef GC_NO_THREADS_DISCOVERY
 
   STATIC mach_port_t GC_mach_handler_thread = 0;
   STATIC GC_bool GC_use_mach_handler_thread = FALSE;
@@ -453,7 +453,7 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
   return changed;
 }
 
-#endif /* !DARWIN_SUSPEND_GC_THREADS */
+#endif /* !GC_NO_THREADS_DISCOVERY */
 
 #ifdef MPROTECT_VDB
   GC_INNER void GC_mprotect_stop(void);
@@ -490,7 +490,7 @@ GC_INNER void GC_stop_world(void)
 # endif /* PARALLEL_MARK */
 
   if (GC_query_task_threads) {
-#   ifndef DARWIN_SUSPEND_GC_THREADS
+#   ifndef GC_NO_THREADS_DISCOVERY
       GC_bool changed;
       thread_act_array_t act_list, prev_list;
       mach_msg_type_number_t listcount, prevcount;
@@ -530,7 +530,7 @@ GC_INNER void GC_stop_world(void)
         mach_port_deallocate(my_task, prev_list[i]);
       vm_deallocate(my_task, (vm_address_t)act_list,
                     sizeof(thread_t) * listcount);
-#   endif /* !DARWIN_SUSPEND_GC_THREADS */
+#   endif /* !GC_NO_THREADS_DISCOVERY */
 
   } else {
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
@@ -601,7 +601,7 @@ GC_INNER void GC_start_world(void)
 # endif
 
   if (GC_query_task_threads) {
-#   ifndef DARWIN_SUSPEND_GC_THREADS
+#   ifndef GC_NO_THREADS_DISCOVERY
       int j = GC_mach_threads_count;
       kern_return_t kern_result;
       thread_act_array_t act_list;
@@ -646,7 +646,7 @@ GC_INNER void GC_start_world(void)
       }
       vm_deallocate(my_task, (vm_address_t)act_list,
                     sizeof(thread_t) * listcount);
-#   endif /* !DARWIN_SUSPEND_GC_THREADS */
+#   endif /* !GC_NO_THREADS_DISCOVERY */
 
   } else {
     mach_port_t my_thread = mach_thread_self();
index e9dfb6f5275cb811132d88f393b53966ac52d8a5..80bb9f897d03ade22a914e444c73360278589153 100644 (file)
@@ -437,9 +437,18 @@ ENABLE_TRACE    Enables the GC_TRACE=addr environment setting to do its job.
 
 DARWIN_DONT_PARSE_STACK         Causes the Darwin port to discover thread
   stack bounds in the same way as other pthread ports, without trying to
-  walk the frames on the stack.  This is recommended only as a fallback for
+  walk the frames on the stack.  This is recommended only as a fall-back for
   applications that don't support proper stack unwinding.
 
+GC_NO_THREADS_DISCOVERY (Darwin and Win32+DLL only)     Exclude DllMain-based
+  (on Windows) and task-threads-based (on Darwin) thread registration support.
+
+GC_DISCOVER_TASK_THREADS (Darwin and Win32+DLL only)    Compile the collector
+  with the implicitly turned on task-threads-based (on Darwin) or
+  DllMain-based (on Windows) approach of threads registering.  Only for
+  compatibility and for the case when it is not possible to call
+  GC_use_threads_discovery() early (before other GC calls).
+
 USE_PROC_FOR_LIBRARIES  Causes the Linux collector to treat writable
   memory mappings (as reported by /proc) as roots, if it doesn't have
   other information about them.  It no longer traverses dynamic loader
@@ -477,9 +486,6 @@ GC_PREFER_MPROTECT_VDB  Choose MPROTECT_VDB manually in case of multiple
   virtual dirty bit strategies are implemented (at present useful on Win32
   to force MPROTECT_VDB strategy instead of the default GWW_VDB one).
 
-GC_NO_DLLMAIN (Win32+DLL only)  Exclude DllMain-based thread registration
-  support.
-
 GC_IGNORE_GCJ_INFO      Disable GCJ-style type information (useful for
   debugging on WinCE).
 
index e93df255020da5ed04a7fd5e853d5194f5eb2985..2e43b63ee72d383dc58bd0b1e58b5dd73de8a182 100644 (file)
@@ -181,7 +181,7 @@ This version of the collector by default handles threads similarly
 to other platforms.  James Clark's code which tracks threads attached
 to the collector DLL still exists, but requires that both
 - the collector is built in a DLL with GC_DLL defined, and
-- GC_use_DllMain() is called before GC initialization, which
+- GC_use_threads_discovery() is called before GC initialization, which
   in turn must happen before creating additional threads.
 We generally recommend avoiding this if possible, since it seems to
 be less than 100% reliable.
index 8019e89120775f4d0fd2141137af6f174a37a813..6a3f9ec93f07ddcef573bbd5eed554b5236e466a 100644 (file)
@@ -1032,6 +1032,15 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
         /* GC_NO_THREADS is not returned by any GC function anymore.    */
 #define GC_UNIMPLEMENTED 3 /* Not yet implemented on this platform.     */
 
+#if defined(GC_DARWIN_THREADS) || defined(GC_WIN32_THREADS)
+  /* Use implicit thread registration and processing (via Win32 DllMain */
+  /* or Darwin task_threads).  Deprecated.  Must be called before       */
+  /* GC_INIT() and other GC routines.  Should be avoided if             */
+  /* GC_pthread_create, GC_beginthreadex (or GC_CreateThread) could be  */
+  /* called instead.  Disables parallelized GC on Win32.                */
+  GC_API void GC_CALL GC_use_threads_discovery(void);
+#endif
+
 #ifdef GC_THREADS
   /* Return the signal number (constant) used by the garbage collector  */
   /* to suspend threads on POSIX systems.  Return -1 otherwise.         */
@@ -1058,7 +1067,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
   /* (which redefines some system functions) before calling the system  */
   /* thread creation function.                                          */
   /* It is also always done implicitly on some platforms if             */
-  /* GC_use_DllMain() is called at start-up.  Except for the            */
+  /* GC_use_threads_discovery() is called at start-up.  Except for the  */
   /* latter case, the explicit call is normally required for threads    */
   /* created by third-party libraries.                                  */
   GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *);
@@ -1257,7 +1266,7 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
     /* (and call GC_unregister_my_thread before thread termination), so */
     /* that they will be recorded in the thread table.  For backward    */
     /* compatibility, it is possible to build the GC with GC_DLL        */
-    /* defined, and to call GC_use_DllMain().  This implicitly          */
+    /* defined, and to call GC_use_threads_discovery.  This implicitly  */
     /* registers all created threads, but appears to be less robust.    */
     /* Currently the collector expects all threads to fall through and  */
     /* terminate normally, or call GC_endthreadex() or GC_ExitThread,   */
@@ -1305,11 +1314,8 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
 #   define WinMain GC_WinMain
 # endif
 
-  /* Use implicit thread registration via DllMain.  Deprecated.  Must   */
-  /* be called before GC_INIT() and other GC routines.  Should be       */
-  /* avoided if GC_beginthreadex() or GC_CreateThread() could be called */
-  /* instead.                                                           */
-  GC_API void GC_CALL GC_use_DllMain(void);
+  /* For compatibility only. */
+# define GC_use_DllMain GC_use_threads_discovery
 
 # ifndef GC_NO_THREAD_REDIRECTS
 #   define CreateThread GC_CreateThread
index 6bbba1b727256b6f23c4904cafbdb5033bb24092..becafccd3c36bea54b89cf1ce21a087958a4a90f 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -3886,7 +3886,7 @@ GC_INNER void GC_mprotect_resume(void)
   GC_mprotect_thread_notify(ID_RESUME);
 }
 
-# ifndef DARWIN_SUSPEND_GC_THREADS
+# ifndef GC_NO_THREADS_DISCOVERY
     GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
 # endif
 
@@ -3912,7 +3912,7 @@ STATIC void *GC_mprotect_thread(void *arg)
   } msg;
   mach_msg_id_t id;
 
-# if defined(THREADS) && !defined(DARWIN_SUSPEND_GC_THREADS)
+# if defined(THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
     GC_darwin_register_mach_handler_thread(mach_thread_self());
 # endif
 
index beb7e41f078bd804f73019360853fbdbf8930479..6041a66a260a2850005ada7d1e1ff6a2c76f9096 100644 (file)
@@ -321,7 +321,7 @@ static ptr_t marker_sp[MAX_MARKERS - 1] = {0};
   static ptr_t marker_bsp[MAX_MARKERS - 1] = {0};
 #endif
 
-#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_SUSPEND_GC_THREADS)
+#if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
   static mach_port_t marker_mach_threads[MAX_MARKERS - 1] = {0};
 
   /* Used only by GC_suspend_thread_list().     */
@@ -348,7 +348,7 @@ STATIC void * GC_mark_thread(void * id)
 # ifdef IA64
     marker_bsp[(word)id] = GC_save_regs_in_stack();
 # endif
-# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_SUSPEND_GC_THREADS)
+# if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
     marker_mach_threads[(word)id] = mach_thread_self();
 # endif
 
index b221bd35083cfd6848f75c63181d4d1086c70390..c2efc82d4dd5c6c0a95a70940aa686227cb27635 100644 (file)
@@ -50,7 +50,7 @@
 
 # include "gc_typed.h"
 # include "private/gc_priv.h"   /* For output, locking, MIN_WORDS,      */
-                                /* and some statistics, and gcconfig.h. */
+                                /* some statistics and gcconfig.h.      */
 
 # if defined(MSWIN32) || defined(MSWINCE)
 #   include <windows.h>
@@ -1529,9 +1529,11 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
     HANDLE win_thr_h;
 # endif
   DWORD thread_id;
-# if defined(GC_DLL) && !defined(GC_NO_DLLMAIN) && !defined(MSWINCE) \
-        && !defined(THREAD_LOCAL_ALLOC) && !defined(PARALLEL_MARK)
-    GC_use_DllMain();  /* Test with implicit thread registration if possible. */
+# if defined(GC_DLL) && !defined(GC_NO_THREADS_DISCOVERY) \
+        && !defined(MSWINCE) && !defined(THREAD_LOCAL_ALLOC) \
+        && !defined(PARALLEL_MARK)
+    GC_use_threads_discovery();
+                /* Test with implicit thread registration if possible. */
     GC_printf("Using DllMain to track threads\n");
 # endif
   GC_COND_INIT();
@@ -1643,6 +1645,12 @@ int main(void)
 #   ifdef PTW32_STATIC_LIB
         pthread_win32_process_attach_np ();
         pthread_win32_thread_attach_np ();
+#   endif
+#   if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY) \
+        && !defined(DARWIN_DONT_PARSE_STACK) && !defined(THREAD_LOCAL_ALLOC)
+      /* Test with the Darwin implicit thread registration. */
+      GC_use_threads_discovery();
+      GC_printf("Using Darwin task-threads-based world stop and push\n");
 #   endif
     GC_COND_INIT();
 
index 05c7c565dad36e7fe0737498f861f0e5fedf91eb..9e0876ef4756d18bf18511de56bf0fb8a3c7dc38 100644 (file)
 
 /* DllMain-based thread registration is currently incompatible  */
 /* with thread-local allocation, pthreads and WinCE.            */
-#if defined(GC_DLL) && !defined(GC_NO_DLLMAIN) && !defined(MSWINCE) \
+#if defined(GC_DLL) && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
         && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
 # include "atomic_ops.h"
 
-  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                   */
-  /* GC_win32_dll_threads is set, all threads in the process    */
+  /* the setting of GC_win32_dll_threads.                       */
+  /* If GC_win32_dll_threads is set, all threads in the process */
   /* are implicitly registered with the GC by DllMain.          */
   /* No explicit registration is required, and attempts at      */
   /* explicit registration are ignored.  This mode is           */
   /* In this mode access to the thread table is lock-free.      */
   /* Hence there is a static limit on the number of threads.    */
 
-  /* If GC_win32_dll_threads is FALSE, or the collector is      */
-  /* built without GC_DLL defined, things operate in a way      */
+# ifdef GC_DISCOVER_TASK_THREADS
+    /* GC_DISCOVER_TASK_THREADS should be used if DllMain-based */
+    /* thread registration is required but it is impossible to  */
+    /* call GC_use_threads_discovery before other GC routines.  */
+#   define GC_win32_dll_threads TRUE
+# else
+    STATIC GC_bool GC_win32_dll_threads = FALSE;
+    /* GC_win32_dll_threads must be set (if needed) at the      */
+    /* application initialization time, i.e. before any         */
+    /* collector or thread calls.  We make it a "dynamic"       */
+    /* option only to avoid multiple library versions.          */
+# endif
+
+#else
+  /* If GC_win32_dll_threads is FALSE (or the collector is      */
+  /* built without GC_DLL defined), things operate in a way     */
   /* that is very similar to Posix platforms, and new threads   */
   /* must be registered with the collector, e.g. by using       */
   /* preprocessor-based interception of the thread primitives.  */
   /* the basic collector rely on such facilities, but an        */
   /* optional package that intercepts thread calls this way     */
   /* would probably be nice.                                    */
-
-  /* GC_win32_dll_threads must be set at initialization time,   */
-  /* i.e. before any collector or thread calls.  We make it a   */
-  /* "dynamic" option only to avoid multiple library versions.  */
-#else
-# ifndef GC_NO_DLLMAIN
-#   define GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
+#   define GC_NO_THREADS_DISCOVERY
 # endif
 # define GC_win32_dll_threads FALSE
 # undef MAX_THREADS
 # define MAX_THREADS 1 /* dll_thread_table[] is always empty.   */
-#endif
+#endif /* GC_NO_THREADS_DISCOVERY */
 
 /* We have two versions of the thread table.  Which one */
 /* we us depends on whether or not GC_win32_dll_threads */
@@ -150,17 +158,20 @@ GC_INNER GC_bool GC_need_to_lock = FALSE;
 
 static GC_bool parallel_initialized = FALSE;
 
-/* GC_use_DllMain() is currently incompatible with pthreads and WinCE.  */
-/* It might be possible to get DllMain-based thread registration to     */
-/* work with Cygwin, but if you try, you are on your own.               */
-GC_API void GC_CALL GC_use_DllMain(void)
+/* GC_use_threads_discovery() is currently incompatible with pthreads   */
+/* and WinCE.  It might be possible to get DllMain-based thread         */
+/* registration to work with Cygwin, but if you try it then you are on  */
+/* your own.                                                            */
+GC_API void GC_CALL GC_use_threads_discovery(void)
 {
-# ifdef GC_NO_DLLMAIN
+# ifdef GC_NO_THREADS_DISCOVERY
     ABORT("GC DllMain-based thread registration unsupported");
 # else
     /* Turn on GC_win32_dll_threads. */
     GC_ASSERT(!parallel_initialized);
-    GC_win32_dll_threads = TRUE;
+#   ifndef GC_DISCOVER_TASK_THREADS
+      GC_win32_dll_threads = TRUE;
+#   endif
     GC_init_parallel();
 # endif
 }
@@ -171,8 +182,8 @@ STATIC DWORD GC_main_thread = 0;
 
 struct GC_Thread_Rep {
   union {
-#   ifndef GC_NO_DLLMAIN
-      AO_t in_use;   /* Updated without lock.                */
+#   ifndef GC_NO_THREADS_DISCOVERY
+      AO_t in_use;      /* Updated without lock.                */
                         /* We assert that unused                */
                         /* entries have invalid ids of          */
                         /* zero and zero stack fields.          */
@@ -252,7 +263,7 @@ struct GC_Thread_Rep {
 typedef struct GC_Thread_Rep * GC_thread;
 typedef volatile struct GC_Thread_Rep * GC_vthread;
 
-#ifndef GC_NO_DLLMAIN
+#ifndef GC_NO_THREADS_DISCOVERY
   /* We assumed that volatile ==> memory ordering, at least among       */
   /* volatiles.  This code should consistently use atomic_ops.          */
   STATIC volatile GC_bool GC_please_stop = FALSE;
@@ -267,7 +278,7 @@ typedef volatile struct GC_Thread_Rep * GC_vthread;
  * If we notice this in the middle of marking.
  */
 
-#ifndef GC_NO_DLLMAIN
+#ifndef GC_NO_THREADS_DISCOVERY
   STATIC AO_t GC_attached_thread = FALSE;
 #endif
 
@@ -276,7 +287,7 @@ typedef volatile struct GC_Thread_Rep * GC_vthread;
   /* since GC_attached_thread was explicitly reset.               */
   GC_bool GC_started_thread_while_stopped(void)
   {
-#   ifndef GC_NO_DLLMAIN
+#   ifndef GC_NO_THREADS_DISCOVERY
       AO_t result;
 
       if (GC_win32_dll_threads) {
@@ -284,8 +295,8 @@ typedef volatile struct GC_Thread_Rep * GC_vthread;
         result = AO_load(&GC_attached_thread);
         if (result) {
           AO_store(&GC_attached_thread, FALSE);
+          return TRUE;
         }
-        return ((GC_bool)result);
       }
 #   endif
     return FALSE;
@@ -365,13 +376,11 @@ STATIC GC_thread GC_new_thread(DWORD id)
 STATIC GC_bool GC_in_thread_creation = FALSE;
                                 /* Protected by allocation lock. */
 
-/*
- * This may be called from DllMain, and hence operates under unusual
- * constraints.  In particular, it must be lock-free if GC_win32_dll_threads
- * is set.  Always called from the thread being added.
- * If GC_win32_dll_threads is not set, we already hold the allocation lock,
- * except possibly during single-threaded start-up code.
- */
+/* This may be called from DllMain, and hence operates under unusual    */
+/* constraints.  In particular, it must be lock-free if                 */
+/* GC_win32_dll_threads is set.  Always called from the thread being    */
+/* added.  If GC_win32_dll_threads is not set, we already hold the      */
+/* allocation lock except possibly during single-threaded startup code. */
 STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
                                              DWORD thread_id)
 {
@@ -389,7 +398,7 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
 #   endif
 # endif
 
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       int i;
       /* It appears to be unsafe to acquire a lock here, since this     */
@@ -471,7 +480,7 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
 # endif
   if (me -> stack_base == NULL)
     ABORT("Bad stack base in GC_register_my_thread_inner");
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       if (GC_please_stop) {
         AO_store(&GC_attached_thread, TRUE);
@@ -510,7 +519,7 @@ GC_INLINE LONG GC_get_max_thread_index(void)
 /* Also used (for assertion checking only) from thread_local_alloc.c.   */
 STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
 {
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       int i;
       LONG my_max = GC_get_max_thread_index();
@@ -522,14 +531,10 @@ STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
            i++) {
         /* empty */
       }
-      if (i > my_max) {
-        return 0;
-      } else {
-        return (GC_thread)(dll_thread_table + i);
-      }
-    }
+      return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
+    } else
 # endif
-  {
+  /* else */ {
     word hv = THREAD_TABLE_INDEX(thread_id);
     register GC_thread p = GC_threads[hv];
 
@@ -592,8 +597,8 @@ GC_INNER unsigned char *GC_check_finalizer_nested(void)
 /* lock may be required for fault handling.                             */
 #if defined(MPROTECT_VDB)
 # define UNPROTECT_THREAD(t) \
-    if (GC_dirty_maintained && !GC_win32_dll_threads && \
-        t != &first_thread) { \
+    if (!GC_win32_dll_threads && GC_dirty_maintained \
+        && t != &first_thread) { \
       GC_ASSERT(SMALL_OBJ(GC_size(t))); \
       GC_remove_protection(HBLKPTR(t), 1, FALSE); \
     }
@@ -614,7 +619,7 @@ STATIC void GC_delete_gc_thread(GC_vthread gc_id)
 # ifndef MSWINCE
     CloseHandle(gc_id->handle);
 # endif
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       /* This is intended to be lock-free.                              */
       /* It is either called synchronously from the thread being        */
@@ -700,7 +705,7 @@ 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_NO_DLLMAIN) && !defined(PARALLEL_MARK)
+# if !defined(GC_NO_THREADS_DISCOVERY) && !defined(PARALLEL_MARK)
     /* GC_init() doesn't call GC_init_parallel() in this case.  */
     parallel_initialized = TRUE;
 # endif
@@ -729,18 +734,19 @@ 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();
   DCL_LOCK_STATE;
 
   /* 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(). */
+      /* Can't happen: see GC_use_threads_discovery(). */
       GC_ASSERT(FALSE);
+#   else
+      /* FIXME: Should we just ignore this? */
+      GC_delete_thread(GetCurrentThreadId());
 #   endif
-    /* FIXME: Should we just ignore this? */
-    GC_delete_thread(t);
   } else {
+    DWORD t = GetCurrentThreadId();
     LOCK();
 #   if defined(THREAD_LOCAL_ALLOC)
       {
@@ -862,7 +868,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
   /* Assumes we do NOT hold the allocation lock.                */
   STATIC GC_thread GC_lookup_pthread(pthread_t id)
   {
-#   ifndef GC_NO_DLLMAIN
+#   ifndef GC_NO_THREADS_DISCOVERY
       if (GC_win32_dll_threads) {
         int i;
         LONG my_max = GC_get_max_thread_index();
@@ -875,11 +881,10 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
              i++) {
           /* empty */
         }
-        if (i > my_max) return 0;
-        return (GC_thread)(dll_thread_table + i);
-      }
+        return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
+      } else
 #   endif
-    {
+    /* else */ {
       /* We first try the cache.  If that fails, we use a very slow     */
       /* approach.                                                      */
       word hv_guess = THREAD_TABLE_INDEX(GET_PTHREAD_MAP_CACHE(id));
@@ -910,7 +915,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
 void GC_push_thread_structures(void)
 {
   GC_ASSERT(I_HOLD_LOCK());
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       /* Unlike the other threads implementations, the thread table here */
       /* contains no pointers to the collectable heap.  Thus we have     */
@@ -1007,7 +1012,7 @@ GC_INNER void GC_stop_world(void)
     }
 # endif /* PARALLEL_MARK */
 
-# if !defined(GC_NO_DLLMAIN) || defined(GC_ASSERTIONS)
+# if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
     GC_please_stop = TRUE;
 # endif
 # ifndef CYGWIN32
@@ -1022,7 +1027,7 @@ GC_INNER void GC_stop_world(void)
       GC_write_disabled = TRUE;
 #   endif
 # endif
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       int i;
       int my_max;
@@ -1100,7 +1105,7 @@ GC_INNER void GC_start_world(void)
       }
     }
   }
-# if !defined(GC_NO_DLLMAIN) || defined(GC_ASSERTIONS)
+# if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
     GC_please_stop = FALSE;
 # endif
 }
@@ -1305,7 +1310,7 @@ GC_INNER void GC_push_all_stacks(void)
     unsigned nthreads = 0;
 # endif
   word total_size = 0;
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     if (GC_win32_dll_threads) {
       int i;
       LONG my_max = GC_get_max_thread_index();
@@ -2269,7 +2274,7 @@ GC_INNER void GC_thr_init(void)
         HMODULE hK32;
         /* SignalObjectAndWait() API call works only under NT.          */
 #     endif
-      if (GC_markers <= 1 || GC_win32_dll_threads
+      if (GC_win32_dll_threads || GC_markers <= 1
 #         if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) \
                 && !defined(DONT_USE_SIGNALANDWAIT)
             || GC_wnt == FALSE
@@ -2362,7 +2367,7 @@ GC_INNER void GC_thr_init(void)
       LOCK();
       GC_delete_gc_thread(joinee);
       UNLOCK();
-    } /* otherwise dllmain handles it.  */
+    } /* otherwise DllMain handles it.  */
 
 #   if DEBUG_CYGWIN_THREADS
       GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
@@ -2383,43 +2388,43 @@ GC_INNER void GC_thr_init(void)
                                const pthread_attr_t *attr,
                                void *(*start_routine)(void *), void *arg)
   {
-    int result;
-    struct start_info * si;
-
     if (!parallel_initialized) GC_init_parallel();
              /* make sure GC is initialized (i.e. main thread is attached) */
     if (GC_win32_dll_threads) {
       return pthread_create(new_thread, attr, start_routine, arg);
-    }
-
-    /* This is otherwise saved only in an area mmapped by the thread */
-    /* library, which isn't visible to the collector.            */
-    si = GC_malloc_uncollectable(sizeof(struct start_info));
-    if (0 == si) return(EAGAIN);
-
-    si -> start_routine = start_routine;
-    si -> arg = arg;
-    if (attr != 0 &&
-        pthread_attr_getdetachstate(attr, &si->detached)
-        == PTHREAD_CREATE_DETACHED) {
-      si->detached = TRUE;
-    }
+    } else {
+      int result;
+      struct start_info * si;
+
+      /* This is otherwise saved only in an area mmapped by the thread  */
+      /* library, which isn't visible to the collector.                 */
+      si = GC_malloc_uncollectable(sizeof(struct start_info));
+      if (0 == si) return(EAGAIN);
+
+      si -> start_routine = start_routine;
+      si -> arg = arg;
+      if (attr != 0 &&
+          pthread_attr_getdetachstate(attr, &si->detached)
+          == PTHREAD_CREATE_DETACHED) {
+        si->detached = TRUE;
+      }
 
-#   if DEBUG_CYGWIN_THREADS
-      GC_printf("About to create a thread from 0x%x(0x%x)\n",
-                (int)pthread_self(), (int)GetCurrentThreadId);
-#   endif
-#   if DEBUG_WIN32_PTHREADS
-      GC_printf("About to create a thread from 0x%x(0x%x)\n",
-                (int)(pthread_self()).p, (int)GetCurrentThreadId());
-#   endif
-    GC_need_to_lock = TRUE;
-    result = pthread_create(new_thread, attr, GC_pthread_start, si);
+#     if DEBUG_CYGWIN_THREADS
+        GC_printf("About to create a thread from 0x%x(0x%x)\n",
+                  (int)pthread_self(), (int)GetCurrentThreadId);
+#     endif
+#     if DEBUG_WIN32_PTHREADS
+        GC_printf("About to create a thread from 0x%x(0x%x)\n",
+                  (int)(pthread_self()).p, (int)GetCurrentThreadId());
+#     endif
+      GC_need_to_lock = TRUE;
+      result = pthread_create(new_thread, attr, GC_pthread_start, si);
 
-    if (result) { /* failure */
-        GC_free(si);
+      if (result) { /* failure */
+          GC_free(si);
+      }
+      return(result);
     }
-    return(result);
   }
 
   STATIC void * GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base *sb,
@@ -2547,7 +2552,7 @@ GC_INNER void GC_thr_init(void)
 
 #else /* !GC_PTHREADS */
 
-# ifndef GC_NO_DLLMAIN
+# ifndef GC_NO_THREADS_DISCOVERY
     /* We avoid acquiring locks here, since this doesn't seem to be     */
     /* preemptible.  This may run with an uninitialized collector, in   */
     /* which case we don't do much.  This implies that no threads other */
@@ -2565,7 +2570,7 @@ GC_INNER void GC_thr_init(void)
 #     endif
       static int entry_count = 0;
 
-      if (parallel_initialized && !GC_win32_dll_threads) return TRUE;
+      if (!GC_win32_dll_threads && parallel_initialized) return TRUE;
 
       switch (reason) {
        case DLL_THREAD_ATTACH:
@@ -2598,31 +2603,28 @@ GC_INNER void GC_thr_init(void)
        case DLL_THREAD_DETACH:
         /* We are hopefully running in the context of the exiting thread. */
         GC_ASSERT(parallel_initialized);
-        if (!GC_win32_dll_threads) return TRUE;
-        GC_delete_thread(GetCurrentThreadId());
+        if (GC_win32_dll_threads) {
+          GC_delete_thread(GetCurrentThreadId());
+        }
         break;
 
        case DLL_PROCESS_DETACH:
-        {
+        if (GC_win32_dll_threads) {
           int i;
-          int my_max;
+          int my_max = (int)GC_get_max_thread_index();
 
-          if (!GC_win32_dll_threads) return TRUE;
-          my_max = (int)GC_get_max_thread_index();
           for (i = 0; i <= my_max; ++i) {
            if (AO_load(&(dll_thread_table[i].tm.in_use)))
              GC_delete_gc_thread(dll_thread_table + i);
           }
-
           GC_deinit();
           DeleteCriticalSection(&GC_allocate_ml);
         }
         break;
-
       }
       return TRUE;
     }
-# endif /* !GC_NO_DLLMAIN */
+# endif /* !GC_NO_THREADS_DISCOVERY */
 
 #endif /* !GC_PTHREADS */