diff options
author | Scott Ferguson <scott.ferguson@unity3d.com> | 2020-06-22 08:22:57 -0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2021-07-28 23:37:00 +0300 |
commit | ce05033c1dc3101b5b5d5faf6e9287cec1c36210 (patch) | |
tree | fec3ebdc8bc9ee66094f85bb8ac4a0c367f03ebb /pthread_stop_world.c | |
parent | b104cdc50404d1f18905cc8f07add407241dfc23 (diff) | |
download | bdwgc-ce05033c1dc3101b5b5d5faf6e9287cec1c36210.tar.gz |
Avoid initial 3ms pause on world stop/start with GC_retry_signals (Linux)
(a cherry-pick of commit 09d56ab44 from Unity-Technologies/bdwgc)
The existing GC_retry_signals case would almost always introduce a 3ms
pause when stopping and starting the world. Instead only fallback to
that retry case if the threads haven't responded after a timeout.
* include/private/gc_priv.h [!NO_CLOCK && (NINTENDO_SWITCH
|| ((LINUX && __USE_POSIX199309 || CYGWIN32) && _POSIX_TIMERS)]
(HAVE_CLOCK_GETTIME): Define.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL] (WAIT_UNIT,
RETRY_INTERVAL): Add comment.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL
&& HAVE_CLOCK_GETTIME] (TS_NSEC_ADD): Define.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL]
(resend_lost_signals_retry): New static function.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL] (GC_stop_world,
GC_start_world): Call resend_lost_signals_retry() instead of
resend_lost_signals() and suspend_restart_barrier() (if
GC_retry_signals).
Diffstat (limited to 'pthread_stop_world.c')
-rw-r--r-- | pthread_stop_world.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/pthread_stop_world.c b/pthread_stop_world.c index 420ae97d..4c14cd42 100644 --- a/pthread_stop_world.c +++ b/pthread_stop_world.c @@ -434,8 +434,8 @@ static void suspend_restart_barrier(int n_live_threads) static int resend_lost_signals(int n_live_threads, int (*suspend_restart_all)(void)) { -# define WAIT_UNIT 3000 -# define RETRY_INTERVAL 100000 +# define WAIT_UNIT 3000 /* us */ +# define RETRY_INTERVAL 100000 /* us */ if (n_live_threads > 0) { unsigned long wait_usecs = 0; /* Total wait since retry. */ @@ -479,6 +479,37 @@ static int resend_lost_signals(int n_live_threads, return n_live_threads; } +#ifdef HAVE_CLOCK_GETTIME +# define TS_NSEC_ADD(ts, ns) \ + (ts.tv_nsec += (ns), \ + (void)(ts.tv_nsec >= 1000000L*1000 ? \ + (ts.tv_nsec -= 1000000L*1000, ts.tv_sec++, 0) : 0)) +#endif + +static void resend_lost_signals_retry(int n_live_threads, + int (*suspend_restart_all)(void)) +{ +# if defined(HAVE_CLOCK_GETTIME) && !defined(DONT_TIMEDWAIT_ACK_SEM) +# define TIMEOUT_BEFORE_RESEND 10000 /* us */ + int i; + struct timespec ts; + + if (n_live_threads > 0 && clock_gettime(CLOCK_REALTIME, &ts) == 0) { + TS_NSEC_ADD(ts, TIMEOUT_BEFORE_RESEND * 1000); + /* First, try to wait for the semaphore with some timeout. */ + /* On failure, fallback to WAIT_UNIT pause and resend of the signal. */ + for (i = 0; i < n_live_threads; i++) { + if (0 != sem_timedwait(&GC_suspend_ack_sem, &ts)) + break; /* Wait timed out or any other error. */ + } + /* Update the count of threads to wait the ack from. */ + n_live_threads -= i; + } +# endif + n_live_threads = resend_lost_signals(n_live_threads, suspend_restart_all); + suspend_restart_barrier(n_live_threads); +} + STATIC void GC_restart_handler(int sig) { # if defined(DEBUG_THREADS) @@ -931,9 +962,11 @@ GC_INNER void GC_stop_world(void) } AO_store_release(&GC_world_is_stopped, TRUE); n_live_threads = GC_suspend_all(); - if (GC_retry_signals) - n_live_threads = resend_lost_signals(n_live_threads, GC_suspend_all); - suspend_restart_barrier(n_live_threads); + if (GC_retry_signals) { + resend_lost_signals_retry(n_live_threads, GC_suspend_all); + } else { + suspend_restart_barrier(n_live_threads); + } if (GC_manual_vdb) GC_release_dirty_lock(); /* cannot be done in GC_suspend_all */ # endif @@ -1182,15 +1215,15 @@ GC_INNER void GC_start_world(void) n_live_threads = GC_restart_all(); # ifdef GC_OPENBSD_UTHREADS (void)n_live_threads; -# elif defined(GC_NETBSD_THREADS_WORKAROUND) - if (GC_retry_signals) - n_live_threads = resend_lost_signals(n_live_threads, GC_restart_all); - suspend_restart_barrier(n_live_threads); # else if (GC_retry_signals) { - n_live_threads = resend_lost_signals(n_live_threads, GC_restart_all); - suspend_restart_barrier(n_live_threads); - } + resend_lost_signals_retry(n_live_threads, GC_restart_all); + } /* else */ +# ifdef GC_NETBSD_THREADS_WORKAROUND + else { + suspend_restart_barrier(n_live_threads); + } +# endif # endif # ifdef DEBUG_THREADS GC_log_printf("World started\n"); |