summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-11-19 19:58:51 +0400
committerIvan Maidanski <ivmai@mail.ru>2012-11-19 19:58:51 +0400
commit92cacbaf5b2f1bdc50ec0abc661528372a8f9c8e (patch)
treea2ad92379be216f20ab71521eeab49812358e229
parent2ef705412989d106b05d0b72b40500450bf7cbbe (diff)
downloadbdwgc-92cacbaf5b2f1bdc50ec0abc661528372a8f9c8e.tar.gz
Add public GC_start_mark_threads() to allow parallel marker in fork child
* 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.
-rw-r--r--include/gc.h4
-rw-r--r--misc.c8
-rw-r--r--pthread_support.c25
-rw-r--r--tests/test.c14
-rw-r--r--win32_threads.c31
5 files changed, 67 insertions, 15 deletions
diff --git a/include/gc.h b/include/gc.h
index 4f32b485..c7c4f00b 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -1218,6 +1218,10 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
/* 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 */
diff --git a/misc.c b/misc.c
index 2c197ff6..861f00d7 100644
--- a/misc.c
+++ b/misc.c
@@ -1231,6 +1231,14 @@ GC_API void GC_CALL GC_enable_incremental(void)
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)
diff --git a/pthread_support.c b/pthread_support.c
index b5fe6962..84c95fbf 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -390,12 +390,25 @@ STATIC void * GC_mark_thread(void * id)
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");
@@ -418,16 +431,16 @@ static void start_mark_threads(void)
}
}
# 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);
}
@@ -1054,7 +1067,7 @@ GC_INNER void GC_thr_init(void)
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
@@ -1078,13 +1091,13 @@ GC_INNER void GC_thr_init(void)
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(
diff --git a/tests/test.c b/tests/test.c
index 6e993a99..583df924 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -89,7 +89,7 @@
# 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
@@ -1301,9 +1301,17 @@ void run_one_test(void)
(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);
diff --git a/win32_threads.c b/win32_threads.c
index bddafa0a..45466bee 100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -1704,6 +1704,10 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
/* 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>
@@ -1713,26 +1717,39 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
/* 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);
}
@@ -2442,7 +2459,7 @@ GC_INNER void GC_thr_init(void)
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. */
@@ -2452,7 +2469,7 @@ GC_INNER void GC_thr_init(void)
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
@@ -2490,7 +2507,9 @@ GC_INNER void GC_thr_init(void)
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();