* include/gc.h (GC_start_mark_threads): New API function prototype.
* misc.c (GC_start_mark_threads): New API function definition (empty)
if THREADS but not PARALLEL_MARK or not CAN_HANDLE_FORK.
* pthread_support.c (available_markers_m1): New static variable or
macro (redirecting to GC_markers_m1) depending on CAN_HANDLE_FORK
(only if PARALLEL_MARK).
* win32_threads.c (available_markers_m1): Likewise.
* pthread_support.c (start_mark_threads): Redirect to
GC_start_mark_threads (and decorate with GC_API/GC_CALL) if
CAN_HANDLE_FORK (and PARALLEL_MARK); skip start if parallel markers
are disabled or already started if CAN_HANDLE_FORK; iterate up to
available_markers_m1 (instead of GC_markers_m1); always set
GC_markers_m1 value.
* win32_threads.c (start_mark_threads): Likewise.
* pthread_support.c (GC_thr_init): Set (and test) available_markers_m1
value instead of GC_markers_m1/GC_parallel (only if PARALLEL_MARK).
* win32_threads.c (GC_thr_init): Likewise.
* tests/test.c (NO_TEST_HANDLE_FORK): Do not define if
TEST_HANDLE_FORK.
* tests/test.c (run_one_test): Invoke GC_start_mark_threads (and
additional GC_gcollect) in forked child (only if THREADS but not
NO_TEST_HANDLE_FORK); do not call tiny_reverse_test if not THREADS.
* win32_threads.c (start_mark_threads): Add assertion that the caller
is not holding the allocation lock (to match that in
pthread_support.c) if GC_PTHREADS_PARAMARK.
/* systems. Return -1 otherwise. */
GC_API int GC_CALL GC_get_thr_restart_signal(void);
+ /* Restart marker threads after POSIX fork in child. Meaningless in */
+ /* other situations. Should not be called if fork followed by exec. */
+ GC_API void GC_CALL GC_start_mark_threads(void);
+
/* Explicitly enable GC_register_my_thread() invocation. */
/* Done implicitly if a GC thread-creation function is called (or */
/* implicit thread registration is activated). Otherwise, it must */
GC_init();
}
+#if defined(THREADS) && (!defined(PARALLEL_MARK) || !defined(CAN_HANDLE_FORK))
+ GC_API void GC_CALL GC_start_mark_threads(void)
+ {
+ /* No action since parallel markers are disabled (or no POSIX fork). */
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+ }
+#endif
+
#if defined(MSWIN32) || defined(MSWINCE)
# if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
STATIC pthread_t GC_mark_threads[MAX_MARKERS];
-static void start_mark_threads(void)
+#ifdef CAN_HANDLE_FORK
+ static int available_markers_m1 = 0;
+# define start_mark_threads GC_start_mark_threads
+ GC_API void GC_CALL
+#else
+# define available_markers_m1 GC_markers_m1
+ static void
+#endif
+start_mark_threads(void)
{
int i;
pthread_attr_t attr;
GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef CAN_HANDLE_FORK
+ if (available_markers_m1 <= 0 || GC_parallel) return;
+ /* Skip if parallel markers disabled or already started. */
+# endif
+
INIT_REAL_SYMS(); /* for pthread_create */
if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
}
}
# endif /* HPUX || GC_DGUX386_THREADS */
- for (i = 0; i < GC_markers_m1; ++i) {
+ for (i = 0; i < available_markers_m1; ++i) {
if (0 != REAL_FUNC(pthread_create)(GC_mark_threads + i, &attr,
GC_mark_thread, (void *)(word)i)) {
WARN("Marker thread creation failed, errno = %" WARN_PRIdPTR "\n",
errno);
/* Don't try to create other marker threads. */
- GC_markers_m1 = i;
break;
}
}
+ GC_markers_m1 = i;
pthread_attr_destroy(&attr);
GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
}
WARN("GC_get_nprocs() returned %" WARN_PRIdPTR "\n", GC_nprocs);
GC_nprocs = 2; /* assume dual-core */
# ifdef PARALLEL_MARK
- GC_parallel = FALSE; /* but use only one marker */
+ available_markers_m1 = 0; /* but use only one marker */
# endif
} else {
# ifdef PARALLEL_MARK
if (markers_m1 >= MAX_MARKERS)
markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
}
- GC_markers_m1 = markers_m1;
+ available_markers_m1 = markers_m1;
}
# endif
}
GC_COND_LOG_PRINTF("Number of processors = %d\n", GC_nprocs);
# ifdef PARALLEL_MARK
- if (GC_markers_m1 <= 0) {
+ if (available_markers_m1 <= 0) {
/* Disable parallel marking. */
GC_parallel = FALSE;
GC_COND_LOG_PRINTF(
# if (!defined(THREADS) || !defined(HANDLE_FORK) \
|| (defined(DARWIN) && defined(MPROTECT_VDB) \
&& !defined(NO_INCREMENTAL) && !defined(MAKE_BACK_GRAPH))) \
- && !defined(NO_TEST_HANDLE_FORK)
+ && !defined(NO_TEST_HANDLE_FORK) && !defined(TEST_HANDLE_FORK)
# define NO_TEST_HANDLE_FORK
# endif
(void)GC_call_with_alloc_lock(inc_int_counter, &n_tests);
# ifndef NO_TEST_HANDLE_FORK
if (fork() == 0) {
+# ifdef THREADS
+# ifdef PARALLEL_MARK
+ GC_gcollect(); /* no parallel markers */
+# endif
+ GC_start_mark_threads();
+# endif
GC_gcollect();
- tiny_reverse_test(0);
- GC_gcollect();
+# ifdef THREADS
+ tiny_reverse_test(0);
+ GC_gcollect();
+# endif
if (print_stats)
GC_log_printf("Finished a child process\n");
exit(0);
/* GC_mark_threads[] is unused here unlike that in pthread_support.c */
+# ifndef CAN_HANDLE_FORK
+# define available_markers_m1 GC_markers_m1
+# endif
+
# ifdef GC_PTHREADS_PARAMARK
# include <pthread.h>
/* start_mark_threads is the same as in pthread_support.c except */
/* for thread stack that is assumed to be large enough. */
- static void start_mark_threads(void)
+# ifdef CAN_HANDLE_FORK
+ static int available_markers_m1 = 0;
+# define start_mark_threads GC_start_mark_threads
+ GC_API void GC_CALL
+# else
+ static void
+# endif
+ start_mark_threads(void)
{
int i;
pthread_attr_t attr;
pthread_t new_thread;
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef CAN_HANDLE_FORK
+ if (available_markers_m1 <= 0 || GC_parallel) return;
+ /* Skip if parallel markers disabled or already started. */
+# endif
+
if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
ABORT("pthread_attr_setdetachstate failed");
- for (i = 0; i < GC_markers_m1; ++i) {
+ for (i = 0; i < available_markers_m1; ++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.\n", 0);
/* Don't try to create other marker threads. */
- GC_markers_m1 = i;
break;
}
}
+ GC_markers_m1 = i;
pthread_attr_destroy(&attr);
GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
}
if (markers_m1 >= MAX_MARKERS)
markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
}
- GC_markers_m1 = markers_m1;
+ available_markers_m1 = markers_m1;
}
/* Check whether parallel mode could be enabled. */
HMODULE hK32;
/* SignalObjectAndWait() API call works only under NT. */
# endif
- if (GC_win32_dll_threads || GC_markers_m1 <= 0
+ if (GC_win32_dll_threads || available_markers_m1 <= 0
# if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) \
&& !defined(DONT_USE_SIGNALANDWAIT)
|| GC_wnt == FALSE
GC_register_my_thread_inner(&sb, GC_main_thread);
# ifdef PARALLEL_MARK
- if (GC_parallel)
+# ifndef CAN_HANDLE_FORK
+ if (GC_parallel)
+# endif
{
/* If we are using a parallel marker, actually start helper threads. */
start_mark_threads();