Skip to content

Commit c811cf5

Browse files
committed
Add Base.in_finalizer query
1 parent eb2e968 commit c811cf5

File tree

5 files changed

+39
-0
lines changed

5 files changed

+39
-0
lines changed

base/gcutils.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,23 @@ function disable_finalizers() @inline
162162
ccall(:jl_gc_disable_finalizers_internal, Cvoid, ())
163163
end
164164

165+
"""
166+
GC.in_finalizer()::Bool
167+
168+
Returns `true` if the current task is running a finalizer, returns `false`
169+
otherwise. Will also return `false` within a finalizer which was inlined by the
170+
compiler's eager finalization optimization, or if `finalize` is called on the
171+
finalizer directly.
172+
173+
The result of this function may be useful, for example, when a finalizer must
174+
wait on a resource to become available; instead of polling the resource in a
175+
`yield` loop (which is not legal to execute within a task running finalizers),
176+
busy polling or an `@async` continuation could be used instead.
177+
"""
178+
function in_finalizer() @inline
179+
ccall(:jl_gc_is_in_finalizer, Int8, ()) > 0
180+
end
181+
165182
"""
166183
GC.@preserve x1 x2 ... xn expr
167184

src/gc.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,11 @@ JL_DLLEXPORT void jl_gc_enable_finalizers(jl_task_t *ct, int on)
488488
}
489489
}
490490

491+
JL_DLLEXPORT int8_t jl_gc_is_in_finalizer(void)
492+
{
493+
return jl_current_task->ptls->in_finalizer;
494+
}
495+
491496
static void schedule_all_finalizers(arraylist_t *flist) JL_NOTSAFEPOINT
492497
{
493498
void **items = flist->items;

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
XX(jl_gc_get_max_memory) \
176176
XX(jl_gc_internal_obj_base_ptr) \
177177
XX(jl_gc_is_enabled) \
178+
XX(jl_gc_is_in_finalizer) \
178179
XX(jl_gc_live_bytes) \
179180
XX(jl_gc_managed_malloc) \
180181
XX(jl_gc_managed_realloc) \

src/julia_threads.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ JL_DLLEXPORT void jl_gc_disable_finalizers_internal(void);
365365
JL_DLLEXPORT void jl_gc_enable_finalizers_internal(void);
366366
JL_DLLEXPORT void jl_gc_run_pending_finalizers(struct _jl_task_t *ct);
367367
extern JL_DLLEXPORT _Atomic(int) jl_gc_have_pending_finalizers;
368+
JL_DLLEXPORT int8_t jl_gc_is_in_finalizer(void);
368369

369370
JL_DLLEXPORT void jl_wakeup_thread(int16_t tid);
370371

test/misc.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,3 +1386,18 @@ end
13861386
@test (@allocations "a") == 0
13871387
@test (@allocations "a" * "b") == 1
13881388
end
1389+
1390+
@testset "in_finalizer" begin
1391+
@test !GC.in_finalizer()
1392+
1393+
in_fin = Ref{Any}()
1394+
wait(@async begin
1395+
r = Ref(1)
1396+
finalizer(r) do _
1397+
in_fin[] = GC.in_finalizer()
1398+
end
1399+
nothing
1400+
end)
1401+
GC.gc(true); yield()
1402+
@test in_fin[]
1403+
end

0 commit comments

Comments
 (0)