diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2012-11-19 19:58:51 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2012-11-19 19:58:51 +0400 |
commit | 92cacbaf5b2f1bdc50ec0abc661528372a8f9c8e (patch) | |
tree | a2ad92379be216f20ab71521eeab49812358e229 | |
parent | 2ef705412989d106b05d0b72b40500450bf7cbbe (diff) | |
download | bdwgc-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.h | 4 | ||||
-rw-r--r-- | misc.c | 8 | ||||
-rw-r--r-- | pthread_support.c | 25 | ||||
-rw-r--r-- | tests/test.c | 14 | ||||
-rw-r--r-- | win32_threads.c | 31 |
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 */ @@ -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(); |