From: Ivan Maidanski Date: Sun, 1 Dec 2013 15:01:46 +0000 (+0400) Subject: New macro (GC_ALWAYS_MULTITHREADED) to set multi-threaded mode implicitly X-Git-Tag: gc7_6_0~312 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d5c65315b;p=gc New macro (GC_ALWAYS_MULTITHREADED) to set multi-threaded mode implicitly * darwin_stop_world.c (GC_use_threads_discovery): Skip assertion on GC_need_to_lock if GC_ALWAYS_MULTITHREADED. * misc.c (GC_init): Likewise. * doc/README.macros (GC_ALWAYS_MULTITHREADED): Document. * include/gc.h (GC_allow_register_threads): Update comment (regarding GC_ALWAYS_MULTITHREADED). * include/private/gc_locks.h (I_HOLD_LOCK): Reformat code. * include/private/gc_locks.h (GC_need_to_lock): Define as macro (to TRUE) if GC_ALWAYS_MULTITHREADED defined. * include/private/gc_locks.h (LOCK, UNLOCK): Define to UNCOND_[UN]LOCK if GC_ALWAYS_MULTITHREADED. * misc.c (GC_init): Call GC_init_parallel() if GC_ALWAYS_MULTITHREADED but not GC_NO_THREADS_DISCOVERY (only for Win32, needed since GC_allow_register_threads does nothing if GC_ALWAYS_MULTITHREADED). * misc.c (IF_NEED_TO_LOCK): Ignore GC_parallel if GC_ALWAYS_MULTITHREADED (since GC_need_to_lock is always true). * pthread_support.c (GC_need_to_lock): Do not define varaible if GC_ALWAYS_MULTITHREADED (since defined as a macro). * win32_threads.c (GC_need_to_lock): Likewise. * pthread_support.c (GC_allow_register_threads, pthread_create): Do not alter value of GC_need_to_lock if GC_ALWAYS_MULTITHREADED. * win32_threads.c (GC_allow_register_threads, GC_CreateThread, GC_beginthreadex, GC_pthread_create, GC_init_parallel): Likewise. * win32_threads.c (GC_allow_register_threads): Do not alter "parallel_initialized" value if GC_ALWAYS_MULTITHREADED (so that GC_allow_register_threads is a no-op if the macro defined). --- diff --git a/darwin_stop_world.c b/darwin_stop_world.c index 14aa1d36..a6b0a5c7 100644 --- a/darwin_stop_world.c +++ b/darwin_stop_world.c @@ -108,7 +108,9 @@ GC_API void GC_CALL GC_use_threads_discovery(void) # 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 GC_ALWAYS_MULTITHREADED + GC_ASSERT(!GC_need_to_lock); +# endif # ifndef GC_DISCOVER_TASK_THREADS GC_query_task_threads = TRUE; # endif diff --git a/doc/README.macros b/doc/README.macros index 4e93acbc..3cbbf267 100644 --- a/doc/README.macros +++ b/doc/README.macros @@ -395,6 +395,9 @@ USE_COMPILER_TLS Causes thread local allocation to use PARALLEL_MARK Allows the marker to run in multiple threads. Recommended for multiprocessors. +GC_ALWAYS_MULTITHREADED Force multi-threaded mode at GC initialization. + (Turns GC_allow_register_threads into a no-op routine.) + DONT_USE_SIGNALANDWAIT (Win32 only) Use an alternate implementation for marker threads (if PARALLEL_MARK defined) synchronization routines based on InterlockedExchange() (instead of AO_fetch_and_add()) and on multiple diff --git a/include/gc.h b/include/gc.h index ca82fd14..5a793395 100644 --- a/include/gc.h +++ b/include/gc.h @@ -1269,8 +1269,9 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */, /* 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 */ - /* be called from the main (or any previously registered) thread */ + /* implicit thread registration is activated, or the collector is */ + /* compiled with GC_ALWAYS_MULTITHREADED defined). Otherwise, it */ + /* must be called from the main (or any previously registered) thread */ /* between the collector initialization and the first explicit */ /* registering of a thread (it should be called as late as possible). */ GC_API void GC_CALL GC_allow_register_threads(void); diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h index 328d13c2..ba1f900c 100644 --- a/include/private/gc_locks.h +++ b/include/private/gc_locks.h @@ -166,8 +166,8 @@ GC_lock_holder = NUMERIC_THREAD_ID(pthread_self()) # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD # define I_HOLD_LOCK() \ - (!GC_need_to_lock || \ - GC_lock_holder == NUMERIC_THREAD_ID(pthread_self())) + (!GC_need_to_lock \ + || GC_lock_holder == NUMERIC_THREAD_ID(pthread_self())) # ifndef NUMERIC_THREAD_ID_UNIQUE # define I_DONT_HOLD_LOCK() 1 /* Conservatively say yes */ # else @@ -181,7 +181,11 @@ # define EXIT_GC() GC_collecting = 0; GC_INNER void GC_lock(void); # endif /* GC_PTHREADS with linux_threads.c implementation */ - GC_EXTERN GC_bool GC_need_to_lock; +# ifdef GC_ALWAYS_MULTITHREADED +# define GC_need_to_lock TRUE +# else + GC_EXTERN GC_bool GC_need_to_lock; +# endif # else /* !THREADS */ # define LOCK() (void)0 @@ -196,7 +200,7 @@ # endif /* !THREADS */ #if defined(UNCOND_LOCK) && !defined(LOCK) -# ifdef LINT2 +# if defined(LINT2) || defined(GC_ALWAYS_MULTITHREADED) /* Instruct code analysis tools not to care about GC_need_to_lock */ /* influence to LOCK/UNLOCK semantic. */ # define LOCK() UNCOND_LOCK() diff --git a/misc.c b/misc.c index c0ba6f4d..3ca8ad94 100644 --- a/misc.c +++ b/misc.c @@ -853,7 +853,9 @@ GC_API void GC_CALL GC_init(void) /* then. Thus we really don't hold any locks, and can */ /* in fact safely initialize them here. */ # ifdef THREADS - GC_ASSERT(!GC_need_to_lock); +# ifndef GC_ALWAYS_MULTITHREADED + GC_ASSERT(!GC_need_to_lock); +# endif # ifdef SN_TARGET_PS3 { pthread_mutexattr_t mattr; @@ -1214,7 +1216,9 @@ GC_API void GC_CALL GC_init(void) /* The rest of this again assumes we don't really hold */ /* the allocation lock. */ -# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) +# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) \ + || (defined(GC_ALWAYS_MULTITHREADED) && defined(GC_WIN32_THREADS) \ + && !defined(GC_NO_THREADS_DISCOVERY)) /* Make sure marker threads are started and thread local */ /* allocation is initialized, in case we didn't get */ /* called from GC_init_parallel. */ @@ -1293,7 +1297,7 @@ GC_API void GC_CALL GC_enable_incremental(void) } # ifdef THREADS -# ifdef PARALLEL_MARK +# if defined(PARALLEL_MARK) && !defined(GC_ALWAYS_MULTITHREADED) # define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x # else # define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x diff --git a/pthread_support.c b/pthread_support.c index c00b93d5..dbdf50b7 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -274,7 +274,9 @@ static GC_bool parallel_initialized = FALSE; -GC_INNER GC_bool GC_need_to_lock = FALSE; +#ifndef GC_ALWAYS_MULTITHREADED + GC_INNER GC_bool GC_need_to_lock = FALSE; +#endif STATIC int GC_nprocs = 1; /* Number of processors. We may not have */ @@ -1544,7 +1546,9 @@ 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(pthread_self()) != 0); - GC_need_to_lock = TRUE; /* We are multi-threaded now. */ +# ifndef GC_ALWAYS_MULTITHREADED + GC_need_to_lock = TRUE; /* We are multi-threaded now. */ +# endif } GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb) @@ -1738,7 +1742,9 @@ GC_API int WRAP_FUNC(pthread_create)(pthread_t *new_thread, GC_log_printf("About to start new thread from thread %p\n", (void *)pthread_self()); # endif - GC_need_to_lock = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED + GC_need_to_lock = TRUE; +# endif result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si); diff --git a/win32_threads.c b/win32_threads.c index 4d57bc5e..b73ee192 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -150,7 +150,9 @@ typedef LONG * IE_t; STATIC GC_bool GC_thr_initialized = FALSE; -GC_INNER GC_bool GC_need_to_lock = FALSE; +#ifndef GC_ALWAYS_MULTITHREADED + GC_INNER GC_bool GC_need_to_lock = FALSE; +#endif static GC_bool parallel_initialized = FALSE; @@ -719,12 +721,13 @@ 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_THREADS_DISCOVERY) && !defined(PARALLEL_MARK) - /* GC_init() doesn't call GC_init_parallel() in this case. */ - parallel_initialized = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED +# if !defined(GC_NO_THREADS_DISCOVERY) && !defined(PARALLEL_MARK) + /* GC_init() does not call GC_init_parallel() in this case. */ + parallel_initialized = TRUE; +# endif + GC_need_to_lock = TRUE; /* We are multi-threaded now. */ # endif - GC_need_to_lock = TRUE; /* We are multi-threaded now. */ } GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb) @@ -2265,7 +2268,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, args -> start = lpStartAddress; args -> param = lpParameter; - GC_need_to_lock = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED + GC_need_to_lock = TRUE; +# endif thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start, args, dwCreationFlags, lpThreadId); if (thread_h == 0) GC_free(args); @@ -2318,7 +2323,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, args -> start = (LPTHREAD_START_ROUTINE)start_address; args -> param = arglist; - GC_need_to_lock = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED + GC_need_to_lock = TRUE; +# endif thread_h = _beginthreadex(security, stack_size, (unsigned (__stdcall *)(void *))GC_win32_start, args, initflag, thrdaddr); @@ -2631,7 +2638,9 @@ GC_INNER void GC_thr_init(void) GC_PTHREAD_PTRVAL(pthread_self()), (long)GetCurrentThreadId()); # endif - GC_need_to_lock = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED + GC_need_to_lock = TRUE; +# endif result = pthread_create(new_thread, attr, GC_pthread_start, si); if (result) { /* failure */ @@ -2853,13 +2862,15 @@ GC_INNER void GC_init_parallel(void) /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); - if (GC_win32_dll_threads) { - GC_need_to_lock = TRUE; +# ifndef GC_ALWAYS_MULTITHREADED + if (GC_win32_dll_threads) { + GC_need_to_lock = TRUE; /* Cannot intercept thread creation. Hence we don't know if */ /* other threads exist. However, client is not allowed to */ /* create other threads before collector initialization. */ /* Thus it's OK not to lock before this. */ - } + } +# endif /* Initialize thread local free lists if used. */ # if defined(THREAD_LOCAL_ALLOC) LOCK();