Skip to content

Commit 7c265b1

Browse files
author
Christopher Doris
committed
move to new PythonCall.GC module
1 parent 6ea28a7 commit 7c265b1

File tree

5 files changed

+86
-54
lines changed

5 files changed

+86
-54
lines changed

docs/src/releasenotes.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Release Notes
22

33
## Unreleased
4+
* Adds `PythonCall.GC.disable()` and `PythonCall.GC.enable()`.
45
* Experimental new function `juliacall.interactive()` allows the Julia async event loop to
56
run in the background of the Python REPL.
67
* Experimental new IPython extension `juliacall.ipython` providing the `%jl` and `%%jl`

src/Py.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mutable struct Py
4343
end
4444
export Py
4545

46-
py_finalizer(x::Py) = C.gc_enqueue(getptr(x))
46+
py_finalizer(x::Py) = GC.enqueue(getptr(x))
4747

4848
ispy(::Py) = true
4949
getptr(x::Py) = getfield(x, :ptr)

src/cpython/gc.jl

-52
This file was deleted.

src/gc.jl

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""
2+
Garbarge collection of Python objects.
3+
4+
See `disable` and `enable`.
5+
"""
6+
module GC
7+
8+
import ..PythonCall.C
9+
10+
const ENABLED = Ref(true)
11+
const QUEUE = PyPtr[]
12+
13+
"""
14+
PythonCall.GC.disable()
15+
16+
Disable the PythonCall garbage collector.
17+
18+
This means that whenever a Python object owned by Julia is finalized, it is not immediately
19+
freed but is instead added to a queue of objects to free later when `enable()` is called.
20+
21+
Like most PythonCall functions, you must only call this from the main thread.
22+
"""
23+
function disable()
24+
ENABLED[] = false
25+
return
26+
end
27+
28+
"""
29+
PythonCall.GC.enable()
30+
31+
Re-enable the PythonCall garbage collector.
32+
33+
This frees any Python objects which were finalized while the GC was disabled, and allows
34+
objects finalized in the future to be freed immediately.
35+
36+
Like most PythonCall functions, you must only call this from the main thread.
37+
"""
38+
function enable()
39+
ENABLED[] = true
40+
if !isempty(QUEUE)
41+
C.with_gil(false) do
42+
for ptr in QUEUE
43+
if ptr != C.PyNULL
44+
C.Py_DecRef(ptr)
45+
end
46+
end
47+
end
48+
end
49+
empty!(QUEUE)
50+
return
51+
end
52+
53+
function enqueue(ptr::C.PyPtr)
54+
if ptr != C.PyNULL && C.CTX.is_initialized
55+
if ENABLED[]
56+
C.with_gil(false) do
57+
C.Py_DecRef(ptr)
58+
end
59+
else
60+
push!(QUEUE, ptr)
61+
end
62+
end
63+
return
64+
end
65+
66+
function enqueue_all(ptrs)
67+
if C.CTX.is_initialized
68+
if ENABLED[]
69+
C.with_gil(false) do
70+
for ptr in ptrs
71+
if ptr != C.PyNULL
72+
C.Py_DecRef(ptr)
73+
end
74+
end
75+
end
76+
else
77+
append!(QUEUE, ptrs)
78+
end
79+
end
80+
return
81+
end
82+
83+
end # module GC

src/jlwrap/objectarray.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ PyObjectArray(undef::UndefInitializer, dims::Vararg{Integer,N}) where {N} = PyOb
2323
PyObjectArray{N}(x::AbstractArray{T,N}) where {T,N} = copyto!(PyObjectArray{N}(undef, size(x)), x)
2424
PyObjectArray(x::AbstractArray{T,N}) where {T,N} = PyObjectArray{N}(x)
2525

26-
pyobjectarray_finalizer(x::PyObjectArray) = C.gc_enqueue_all(x.ptrs)
26+
pyobjectarray_finalizer(x::PyObjectArray) = GC.enqueue_all(x.ptrs)
2727

2828
Base.IndexStyle(x) = Base.IndexStyle(x.ptrs)
2929

0 commit comments

Comments
 (0)