Skip to content

Commit e8f23d7

Browse files
authored
improve performance of disabling finalizers in locks (#39153)
helps #38947
1 parent efc9860 commit e8f23d7

File tree

8 files changed

+85
-21
lines changed

8 files changed

+85
-21
lines changed

base/gcutils.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,20 @@ the current Task. Finalizers will only run when the counter is at zero. (Set
114114
`true` for enabling, `false` for disabling). They may still run concurrently on
115115
another Task or thread.
116116
"""
117-
enable_finalizers(on::Bool) = ccall(:jl_gc_enable_finalizers, Cvoid, (Ptr{Cvoid}, Int32,), C_NULL, on)
117+
enable_finalizers(on::Bool) = on ? enable_finalizers() : disable_finalizers()
118+
119+
function enable_finalizers()
120+
Base.@_inline_meta
121+
ccall(:jl_gc_enable_finalizers_internal, Cvoid, ())
122+
if unsafe_load(cglobal(:jl_gc_have_pending_finalizers, Cint)) != 0
123+
ccall(:jl_gc_run_pending_finalizers, Cvoid, (Ptr{Cvoid},), C_NULL)
124+
end
125+
end
126+
127+
function disable_finalizers()
128+
Base.@_inline_meta
129+
ccall(:jl_gc_disable_finalizers_internal, Cvoid, ())
130+
end
118131

119132
"""
120133
GC.@preserve x1 x2 ... xn expr

base/lock.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function trylock(rl::ReentrantLock)
6565
if rl.reentrancy_cnt == 0
6666
rl.locked_by = t
6767
rl.reentrancy_cnt = 1
68-
GC.enable_finalizers(false)
68+
GC.disable_finalizers()
6969
got = true
7070
else
7171
got = false
@@ -93,7 +93,7 @@ function lock(rl::ReentrantLock)
9393
if rl.reentrancy_cnt == 0
9494
rl.locked_by = t
9595
rl.reentrancy_cnt = 1
96-
GC.enable_finalizers(false)
96+
GC.disable_finalizers()
9797
break
9898
end
9999
try
@@ -135,7 +135,7 @@ function unlock(rl::ReentrantLock)
135135
rethrow()
136136
end
137137
end
138-
GC.enable_finalizers(true)
138+
GC.enable_finalizers()
139139
unlock(rl.cond_wait)
140140
end
141141
return
@@ -157,7 +157,7 @@ function unlockall(rl::ReentrantLock)
157157
rethrow()
158158
end
159159
end
160-
GC.enable_finalizers(true)
160+
GC.enable_finalizers()
161161
unlock(rl.cond_wait)
162162
return n
163163
end

base/locks-mt.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ Base.assert_havelock(l::SpinLock) = islocked(l) ? nothing : Base.concurrency_vio
6161
function lock(l::SpinLock)
6262
while true
6363
if _get(l) == 0
64-
GC.enable_finalizers(false)
64+
GC.disable_finalizers()
6565
p = _xchg!(l, 1)
6666
if p == 0
6767
return
6868
end
69-
GC.enable_finalizers(true)
69+
GC.enable_finalizers()
7070
end
7171
ccall(:jl_cpu_pause, Cvoid, ())
7272
# Temporary solution before we have gc transition support in codegen.
@@ -76,20 +76,20 @@ end
7676

7777
function trylock(l::SpinLock)
7878
if _get(l) == 0
79-
GC.enable_finalizers(false)
79+
GC.disable_finalizers()
8080
p = _xchg!(l, 1)
8181
if p == 0
8282
return true
8383
end
84-
GC.enable_finalizers(true)
84+
GC.enable_finalizers()
8585
end
8686
return false
8787
end
8888

8989
function unlock(l::SpinLock)
9090
_get(l) == 0 && error("unlock count must match lock count")
9191
_set!(l, 0)
92-
GC.enable_finalizers(true)
92+
GC.enable_finalizers()
9393
ccall(:jl_cpu_wake, Cvoid, ())
9494
return
9595
end

src/ccall.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,28 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
14811481
tbaa_decorate(tbaa_const, tid);
14821482
return mark_or_box_ccall_result(ctx, tid, retboxed, rt, unionall, static_rt);
14831483
}
1484+
else if (is_libjulia_func(jl_gc_disable_finalizers_internal)
1485+
#ifdef NDEBUG
1486+
|| is_libjulia_func(jl_gc_enable_finalizers_internal)
1487+
#endif
1488+
) {
1489+
JL_GC_POP();
1490+
Value *ptls_i32 = emit_bitcast(ctx, ctx.ptlsStates, T_pint32);
1491+
const int finh_offset = offsetof(jl_tls_states_t, finalizers_inhibited);
1492+
Value *pfinh = ctx.builder.CreateInBoundsGEP(ptls_i32, ConstantInt::get(T_size, finh_offset / 4));
1493+
LoadInst *finh = ctx.builder.CreateAlignedLoad(pfinh, Align(sizeof(int32_t)));
1494+
Value *newval;
1495+
if (is_libjulia_func(jl_gc_disable_finalizers_internal)) {
1496+
newval = ctx.builder.CreateAdd(finh, ConstantInt::get(T_int32, 1));
1497+
}
1498+
else {
1499+
newval = ctx.builder.CreateSelect(ctx.builder.CreateICmpEQ(finh, ConstantInt::get(T_int32, 0)),
1500+
ConstantInt::get(T_int32, 0),
1501+
ctx.builder.CreateSub(finh, ConstantInt::get(T_int32, 1)));
1502+
}
1503+
ctx.builder.CreateStore(newval, pfinh);
1504+
return ghostValue(jl_nothing_type);
1505+
}
14841506
else if (is_libjulia_func(jl_get_current_task)) {
14851507
assert(lrt == T_prjlvalue);
14861508
assert(!isVa && !llvmcall && nccallargs == 0);

src/gc.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ bigval_t *big_objects_marked = NULL;
181181
// `to_finalize` should not have tagged pointers.
182182
arraylist_t finalizer_list_marked;
183183
arraylist_t to_finalize;
184+
int jl_gc_have_pending_finalizers = 0;
184185

185186
NOINLINE uintptr_t gc_get_stack_ptr(void)
186187
{
@@ -261,6 +262,7 @@ static void schedule_finalization(void *o, void *f) JL_NOTSAFEPOINT
261262
{
262263
arraylist_push(&to_finalize, o);
263264
arraylist_push(&to_finalize, f);
265+
jl_gc_have_pending_finalizers = 1;
264266
}
265267

266268
static void run_finalizer(jl_ptls_t ptls, jl_value_t *o, jl_value_t *ff)
@@ -386,19 +388,47 @@ static void run_finalizers(jl_ptls_t ptls)
386388
if (to_finalize.items == to_finalize._space) {
387389
copied_list.items = copied_list._space;
388390
}
391+
jl_gc_have_pending_finalizers = 0;
389392
arraylist_new(&to_finalize, 0);
390393
// This releases the finalizers lock.
391394
jl_gc_run_finalizers_in_list(ptls, &copied_list);
392395
arraylist_free(&copied_list);
393396
}
394397

398+
JL_DLLEXPORT void jl_gc_run_pending_finalizers(jl_ptls_t ptls)
399+
{
400+
if (ptls == NULL)
401+
ptls = jl_get_ptls_states();
402+
if (!ptls->in_finalizer && ptls->locks.len == 0 && ptls->finalizers_inhibited == 0) {
403+
ptls->in_finalizer = 1;
404+
run_finalizers(ptls);
405+
ptls->in_finalizer = 0;
406+
}
407+
}
408+
395409
JL_DLLEXPORT int jl_gc_get_finalizers_inhibited(jl_ptls_t ptls)
396410
{
397411
if (ptls == NULL)
398412
ptls = jl_get_ptls_states();
399413
return ptls->finalizers_inhibited;
400414
}
401415

416+
JL_DLLEXPORT void jl_gc_disable_finalizers_internal(void)
417+
{
418+
jl_ptls_t ptls = jl_get_ptls_states();
419+
ptls->finalizers_inhibited++;
420+
}
421+
422+
JL_DLLEXPORT void jl_gc_enable_finalizers_internal(void)
423+
{
424+
jl_ptls_t ptls = jl_get_ptls_states();
425+
#ifdef NDEBUG
426+
ptls->finalizers_inhibited--;
427+
#else
428+
jl_gc_enable_finalizers(ptls, 1);
429+
#endif
430+
}
431+
402432
JL_DLLEXPORT void jl_gc_enable_finalizers(jl_ptls_t ptls, int on)
403433
{
404434
if (ptls == NULL)
@@ -421,10 +451,8 @@ JL_DLLEXPORT void jl_gc_enable_finalizers(jl_ptls_t ptls, int on)
421451
return;
422452
}
423453
ptls->finalizers_inhibited = new_val;
424-
if (!new_val && old_val && !ptls->in_finalizer && ptls->locks.len == 0) {
425-
ptls->in_finalizer = 1;
426-
run_finalizers(ptls);
427-
ptls->in_finalizer = 0;
454+
if (jl_gc_have_pending_finalizers) {
455+
jl_gc_run_pending_finalizers(ptls);
428456
}
429457
}
430458

src/julia_threads.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ int8_t jl_gc_safe_leave(jl_ptls_t ptls, int8_t state); // Can be a safepoint
341341
JL_DLLEXPORT void (jl_gc_safepoint)(void);
342342

343343
JL_DLLEXPORT void jl_gc_enable_finalizers(jl_ptls_t ptls, int on);
344+
JL_DLLEXPORT void jl_gc_disable_finalizers_internal(void);
345+
JL_DLLEXPORT void jl_gc_enable_finalizers_internal(void);
346+
JL_DLLEXPORT void jl_gc_run_pending_finalizers(jl_ptls_t ptls);
347+
extern JL_DLLEXPORT int jl_gc_have_pending_finalizers;
344348

345349
JL_DLLEXPORT void jl_wakeup_thread(int16_t tid);
346350

src/locks.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,8 @@ static inline void jl_mutex_unlock(jl_mutex_t *lock)
132132
jl_mutex_unlock_nogc(lock);
133133
jl_lock_frame_pop();
134134
JL_SIGATOMIC_END();
135-
if (ptls->locks.len == 0 && ptls->finalizers_inhibited == 0) {
136-
ptls->finalizers_inhibited = 1;
137-
jl_gc_enable_finalizers(ptls, 1); // call run_finalizers (may GC)
135+
if (jl_gc_have_pending_finalizers) {
136+
jl_gc_run_pending_finalizers(ptls); // may GC
138137
}
139138
}
140139

src/rtutils.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,8 @@ JL_DLLEXPORT void jl_eh_restore_state(jl_handler_t *eh)
265265
if (old_defer_signal && !eh->defer_signal) {
266266
jl_sigint_safepoint(ptls);
267267
}
268-
if (unlocks && eh->locks_len == 0 && ptls->finalizers_inhibited == 0) {
269-
// call run_finalizers
270-
ptls->finalizers_inhibited = 1;
271-
jl_gc_enable_finalizers(ptls, 1);
268+
if (jl_gc_have_pending_finalizers && unlocks && eh->locks_len == 0) {
269+
jl_gc_run_pending_finalizers(ptls);
272270
}
273271
}
274272

0 commit comments

Comments
 (0)