summaryrefslogtreecommitdiff
path: root/win32_threads.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-06-01 21:12:40 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-06-01 21:15:32 +0300
commit020b05d7d567926a023dc428cde7b6add246cd65 (patch)
tree4eecedcef1c80113981f5c6ad65bca316ec97617 /win32_threads.c
parentcdcbc1cee7a9b0d9d6d33ba239d06a7b7898f179 (diff)
downloadbdwgc-020b05d7d567926a023dc428cde7b6add246cd65.tar.gz
Prevent (fix) parallel custom mark procs run in single-threaded clients
If the collector is built with parallel marker support then marking is performed in parallel on multi-core targets. Thus, if the client provides custom mark procedures, then they could be executed in parallel. In case of a single-threaded client (developed for the older libgc version with the parallel mark support off), its custom mark procedures might not be prepared to be launched in parallel. Now, the parallel mark threads are not launched, even if available, until the client starts a (user) thread (e.g. calls pthread_create or GC_allow_register_threads) or tells the collector explicitly to start the mark threads (by calling GC_start_mark_threads). * doc/README.macros (GC_ALWAYS_MULTITHREADED): Update documentation. * doc/scale.md (Options for enhanced scalability): Likewise. * include/gc/gc.h [GC_THREADS] (GC_parallel, GC_allow_register_threads): Update comment. * include/gc/gc.h (GC_set_markers_count, GC_start_mark_threads): Likewise. * include/gc/gc_mark.h (GC_mark_proc): Likewise. * include/gc/gc_mark.h (GC_PROC_BYTES, GC_ms_entry): Move upper to be before the comment belonging to GC_mark_proc. * misc.c [THREADS && PARALLEL_MARK] (GC_init): Do not call GC_start_mark_threads_inner(). * misc.c [PARALLEL_MARK] (GC_start_mark_threads): Call GC_start_mark_threads_inner() even if THREAD_SANITIZER or no CAN_HANDLE_FORK. * misc.c [THREADS] (GC_get_parallel): Remove comment. * pthread_support.c [PARALLEL_MARK && !CAN_HANDLE_FORK] (available_markers_m1): Define as a variable. * win32_threads.c [PARALLEL_MARK && !CAN_HANDLE_FORK] (available_markers_m1): Likewise. * pthread_support.c [PARALLEL_MARK && !CAN_HANDLE_FORK] (GC_wait_for_gc_completion): Declare. * pthread_support.c [PARALLEL_MARK && !CAN_HANDLE_FORK] (GC_start_mark_threads_inner): If GC_parallel then return; call GC_wait_for_gc_completion(); set GC_markers_m1 value from available_markers_m1. * win32_threads.c [PARALLEL_MARK && (!GC_PTHREADS_PARAMARK || !CAN_HANDLE_FORK)] (GC_start_mark_threads_inner): Likewise. * pthread_support.c [CAN_HANDLE_FORK && PARALLEL_MARK && THREAD_SANITIZER] (fork_child_proc): Set available_markers_m1 to 0. * pthread_support.c [CAN_HANDLE_FORK]: Move GC_remove_all_threads_but_me() call to be after setting available_markers_m1. * pthread_support.c (GC_allow_register_threads): Call GC_start_mark_threads(). * tests/middle.c (main): Likewise. * win32_threads.c (GC_allow_register_threads): Likewise. * pthread_support.c [PARALLEL_MARK] (pthread_create): Call GC_start_mark_threads() unless GC_parallel or available_markers_m1<=0. * win32_threads.c (START_MARK_THREADS): Define macro (to call GC_start_mark_threads() if PARALLEL_MARK). * win32_threads.c (GC_CreateThread): Call START_MARK_THREADS() (right before set_need_to_lock). * win32_threads.c [!CYGWIN32 && !MSWINCE && !MSWIN_XBOX1 && !NO_CRT] (GC_beginthreadex): Likewise. * win32_threads.c [GC_PTHREADS] (GC_pthread_create): Likewise.
Diffstat (limited to 'win32_threads.c')
-rw-r--r--win32_threads.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/win32_threads.c b/win32_threads.c
index 13402220..584193a9 100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -775,6 +775,7 @@ GC_API void GC_CALL GC_allow_register_threads(void)
GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0);
UNLOCK();
# endif
+ GC_start_mark_threads();
set_need_to_lock();
}
@@ -2097,11 +2098,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
/* GC_mark_threads[] is unused here unlike that in pthread_support.c */
-# ifdef CAN_HANDLE_FORK
- static int available_markers_m1 = 0;
-# else
-# define available_markers_m1 GC_markers_m1
-# endif
+ static int available_markers_m1 = 0;
# ifdef GC_PTHREADS_PARAMARK
# include <pthread.h>
@@ -2132,12 +2129,11 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_ASSERT(I_HOLD_LOCK());
ASSERT_CANCEL_DISABLED();
- if (available_markers_m1 <= 0) return;
+ if (available_markers_m1 <= 0 || GC_parallel) return;
/* Skip if parallel markers disabled or already started. */
-# ifdef CAN_HANDLE_FORK
- if (GC_parallel) return;
- GC_wait_for_gc_completion(TRUE);
+ GC_wait_for_gc_completion(TRUE);
+# ifdef CAN_HANDLE_FORK
/* Reset mark_cv state after forking (as in pthread_support.c). */
{
pthread_cond_t mark_cv_local = PTHREAD_COND_INITIALIZER;
@@ -2164,10 +2160,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
}
# endif /* !NO_MARKER_SPECIAL_SIGMASK */
-# ifdef CAN_HANDLE_FORK
- /* To have proper GC_parallel value in GC_help_marker. */
- GC_markers_m1 = available_markers_m1;
-# endif
+ /* To have proper GC_parallel value in GC_help_marker. */
+ GC_markers_m1 = available_markers_m1;
+
for (i = 0; i < available_markers_m1; ++i) {
marker_last_stack_min[i] = ADDR_LIMIT;
if (EXPECT(0 != pthread_create(&new_thread, &attr, GC_mark_thread,
@@ -2307,11 +2302,13 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_ASSERT(I_HOLD_LOCK());
ASSERT_CANCEL_DISABLED();
- if (available_markers_m1 <= 0) return;
+ if (available_markers_m1 <= 0 || GC_parallel) return;
+ GC_wait_for_gc_completion(TRUE);
GC_ASSERT(GC_fl_builder_count == 0);
/* Initialize GC_marker_cv[] fully before starting the */
/* first helper thread. */
+ GC_markers_m1 = available_markers_m1;
for (i = 0; i < GC_markers_m1; ++i) {
if ((GC_marker_cv[i] = CreateEvent(NULL /* attrs */,
TRUE /* isManualReset */,
@@ -2509,7 +2506,14 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
/* The same implementation as in pthread_support.c. */
required_markers_cnt = markers < MAX_MARKERS ? markers : MAX_MARKERS;
}
-#endif /* PARALLEL_MARK */
+
+# define START_MARK_THREADS() \
+ if (EXPECT(GC_parallel || available_markers_m1 <= 0, TRUE)) {} \
+ else GC_start_mark_threads()
+#else
+
+# define START_MARK_THREADS() (void)0
+#endif /* !PARALLEL_MARK */
/* We have no DllMain to take care of new threads. Thus we */
/* must properly intercept thread creation. */
@@ -2600,6 +2604,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_dirty(args);
REACHABLE_AFTER_DIRTY(lpParameter);
+ START_MARK_THREADS();
set_need_to_lock();
thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
args, dwCreationFlags, lpThreadId);
@@ -2653,6 +2658,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_dirty(args);
REACHABLE_AFTER_DIRTY(arglist);
+ START_MARK_THREADS();
set_need_to_lock();
thread_h = _beginthreadex(security, stack_size,
(unsigned (__stdcall *)(void *))GC_win32_start,
@@ -2987,6 +2993,7 @@ GC_INNER void GC_thr_init(void)
(void *)GC_PTHREAD_PTRVAL(pthread_self()),
(long)GetCurrentThreadId());
# endif
+ START_MARK_THREADS();
set_need_to_lock();
result = pthread_create(new_thread, attr, GC_pthread_start, si);
if (EXPECT(result != 0, FALSE)) GC_free(si); /* failure */