@@ -43,7 +43,8 @@ uint8_t jl_safepoint_enable_cnt[3] = {0, 0, 0};
4343// load/store so that threads waiting for the GC doesn't have to also
4444// fight on the safepoint lock...
4545uv_mutex_t safepoint_lock ;
46- uv_cond_t safepoint_cond ;
46+ uv_cond_t safepoint_cond_begin ;
47+ uv_cond_t safepoint_cond_end ;
4748
4849static void jl_safepoint_enable (int idx ) JL_NOTSAFEPOINT
4950{
@@ -88,7 +89,8 @@ static void jl_safepoint_disable(int idx) JL_NOTSAFEPOINT
8889void jl_safepoint_init (void )
8990{
9091 uv_mutex_init (& safepoint_lock );
91- uv_cond_init (& safepoint_cond );
92+ uv_cond_init (& safepoint_cond_begin );
93+ uv_cond_init (& safepoint_cond_end );
9294 // jl_page_size isn't available yet.
9395 size_t pgsz = jl_getpagesize ();
9496#ifdef _OS_WINDOWS_
@@ -109,6 +111,31 @@ void jl_safepoint_init(void)
109111 jl_safepoint_pages = addr ;
110112}
111113
114+ void jl_gc_wait_for_the_world (void )
115+ {
116+ assert (jl_n_threads );
117+ if (jl_n_threads > 1 )
118+ jl_wake_libuv ();
119+ for (int i = 0 ; i < jl_n_threads ; i ++ ) {
120+ jl_ptls_t ptls2 = jl_all_tls_states [i ];
121+ // This acquire load pairs with the release stores
122+ // in the signal handler of safepoint so we are sure that
123+ // all the stores on those threads are visible.
124+ // We're currently also using atomic store release in mutator threads
125+ // (in jl_gc_state_set), but we may want to use signals to flush the
126+ // memory operations on those threads lazily instead.
127+ while (!jl_atomic_load_relaxed (& ptls2 -> gc_state ) || !jl_atomic_load_acquire (& ptls2 -> gc_state )) {
128+ // Use system mutexes rather than spin locking to minimize wasted CPU time
129+ // while we wait for other threads reach a safepoint.
130+ // This is particularly important when run under rr.
131+ uv_mutex_lock (& safepoint_lock );
132+ if (!jl_atomic_load_relaxed (& ptls2 -> gc_state ))
133+ uv_cond_wait (& safepoint_cond_begin , & safepoint_lock );
134+ uv_mutex_unlock (& safepoint_lock );
135+ }
136+ }
137+ }
138+
112139int jl_safepoint_start_gc (void )
113140{
114141 if (jl_n_threads == 1 ) {
@@ -153,13 +180,14 @@ void jl_safepoint_end_gc(void)
153180 jl_mach_gc_end ();
154181# endif
155182 uv_mutex_unlock (& safepoint_lock );
156- uv_cond_broadcast (& safepoint_cond );
183+ uv_cond_broadcast (& safepoint_cond_end );
157184}
158185
159186void jl_safepoint_wait_gc (void )
160187{
161188 // The thread should have set this is already
162189 assert (jl_atomic_load_relaxed (& jl_current_task -> ptls -> gc_state ) != 0 );
190+ uv_cond_broadcast (& safepoint_cond_begin );
163191 // Use normal volatile load in the loop for speed until GC finishes.
164192 // Then use an acquire load to make sure the GC result is visible on this thread.
165193 while (jl_atomic_load_relaxed (& jl_gc_running ) || jl_atomic_load_acquire (& jl_gc_running )) {
@@ -168,7 +196,7 @@ void jl_safepoint_wait_gc(void)
168196 // This is particularly important when run under rr.
169197 uv_mutex_lock (& safepoint_lock );
170198 if (jl_atomic_load_relaxed (& jl_gc_running ))
171- uv_cond_wait (& safepoint_cond , & safepoint_lock );
199+ uv_cond_wait (& safepoint_cond_end , & safepoint_lock );
172200 uv_mutex_unlock (& safepoint_lock );
173201 }
174202}
0 commit comments