Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify GIL handling #530

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pysrc/juliacall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def args_from_config():
os.environ['PATH'] = libdir

# Open the library
CONFIG['lib'] = lib = c.CDLL(libpath, mode=c.RTLD_GLOBAL)
CONFIG['lib'] = lib = c.PyDLL(libpath, mode=c.RTLD_GLOBAL)

# parse options
argc, argv = args_from_config()
Expand Down
1 change: 0 additions & 1 deletion src/C/C.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ include("consts.jl")
include("pointers.jl")
include("extras.jl")
include("context.jl")
include("gil.jl")
include("api.jl")

function __init__()
Expand Down
120 changes: 57 additions & 63 deletions src/C/context.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,63 +145,61 @@ function init_context()
@require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall)

# Initialize the interpreter
with_gil() do
CTX.is_preinitialized = Py_IsInitialized() != 0
if CTX.is_preinitialized
@assert CTX.which == :PyCall || CTX.matches_pycall isa Bool
CTX.is_preinitialized = Py_IsInitialized() != 0
if CTX.is_preinitialized
@assert CTX.which == :PyCall || CTX.matches_pycall isa Bool
else
@assert CTX.which != :PyCall
# Find ProgramName and PythonHome
script = if Sys.iswindows()
"""
import sys
print(sys.executable)
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.exec_prefix)
"""
else
@assert CTX.which != :PyCall
# Find ProgramName and PythonHome
script = if Sys.iswindows()
"""
import sys
print(sys.executable)
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.exec_prefix)
"""
else
"""
import sys
print(sys.executable)
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_prefix)
sys.stdout.write(":")
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.prefix)
sys.stdout.write(":")
sys.stdout.write(sys.exec_prefix)
"""
end
CTX.pyprogname, CTX.pyhome = readlines(python_cmd(["-c", script]))
"""
import sys
print(sys.executable)
if hasattr(sys, "base_exec_prefix"):
sys.stdout.write(sys.base_prefix)
sys.stdout.write(":")
sys.stdout.write(sys.base_exec_prefix)
else:
sys.stdout.write(sys.prefix)
sys.stdout.write(":")
sys.stdout.write(sys.exec_prefix)
"""
end
CTX.pyprogname, CTX.pyhome = readlines(python_cmd(["-c", script]))

# Set PythonHome
CTX.pyhome_w = Base.cconvert(Cwstring, CTX.pyhome)
Py_SetPythonHome(pointer(CTX.pyhome_w))
# Set PythonHome
CTX.pyhome_w = Base.cconvert(Cwstring, CTX.pyhome)
Py_SetPythonHome(pointer(CTX.pyhome_w))

# Set ProgramName
CTX.pyprogname_w = Base.cconvert(Cwstring, CTX.pyprogname)
Py_SetProgramName(pointer(CTX.pyprogname_w))
# Set ProgramName
CTX.pyprogname_w = Base.cconvert(Cwstring, CTX.pyprogname)
Py_SetProgramName(pointer(CTX.pyprogname_w))

# Start the interpreter and register exit hooks
Py_InitializeEx(0)
atexit() do
CTX.is_initialized = false
if CTX.version === missing || CTX.version < v"3.6"
Py_Finalize()
else
if Py_FinalizeEx() == -1
@warn "Py_FinalizeEx() error"
end
# Start the interpreter and register exit hooks
Py_InitializeEx(0)
atexit() do
CTX.is_initialized = false
if CTX.version === missing || CTX.version < v"3.6"
Py_Finalize()
else
if Py_FinalizeEx() == -1
@warn "Py_FinalizeEx() error"
end
end
end
CTX.is_initialized = true
if Py_AtExit(@cfunction(_atpyexit, Cvoid, ())) == -1
@warn "Py_AtExit() error"
end
end
CTX.is_initialized = true
if Py_AtExit(@cfunction(_atpyexit, Cvoid, ())) == -1
@warn "Py_AtExit() error"
end
end

Expand All @@ -218,20 +216,16 @@ function init_context()
ENV["JULIA_PYTHONCALL_EXE"] = CTX.exe_path::String
end

with_gil() do

# Get the python version
verstr = Base.unsafe_string(Py_GetVersion())
vermatch = match(r"^[0-9.]+", verstr)
if vermatch === nothing
error("Cannot parse version from version string: $(repr(verstr))")
end
CTX.version = VersionNumber(vermatch.match)
v"3.5" ≤ CTX.version < v"4" || error(
"Only Python 3.5+ is supported, this is Python $(CTX.version) at $(CTX.exe_path===missing ? "unknown location" : CTX.exe_path).",
)

# Get the python version
verstr = Base.unsafe_string(Py_GetVersion())
vermatch = match(r"^[0-9.]+", verstr)
if vermatch === nothing
error("Cannot parse version from version string: $(repr(verstr))")
end
CTX.version = VersionNumber(vermatch.match)
v"3.5" ≤ CTX.version < v"4" || error(
"Only Python 3.5+ is supported, this is Python $(CTX.version) at $(CTX.exe_path===missing ? "unknown location" : CTX.exe_path).",
)

@debug "Initialized PythonCall.jl" CTX.is_embedded CTX.is_initialized CTX.exe_path CTX.lib_path CTX.lib_ptr CTX.pyprogname CTX.pyhome CTX.version

Expand Down
24 changes: 0 additions & 24 deletions src/C/gil.jl

This file was deleted.

2 changes: 2 additions & 0 deletions src/C/pointers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const CAPI_FUNC_SIGS = Dict{Symbol,Pair{Tuple,Type}}(
:PyEval_RestoreThread => (Ptr{Cvoid},) => Cvoid,
:PyGILState_Ensure => () => PyGILState_STATE,
:PyGILState_Release => (PyGILState_STATE,) => Cvoid,
:PyGILState_GetThisThreadState => () => Ptr{Cvoid},
:PyGILState_Check => () => Cint,
# IMPORT
:PyImport_ImportModule => (Ptr{Cchar},) => PyPtr,
:PyImport_Import => (PyPtr,) => PyPtr,
Expand Down
8 changes: 3 additions & 5 deletions src/Compat/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@ include("tables.jl")
include("pycall.jl")

function __init__()
C.with_gil() do
init_gui()
init_pyshow()
init_tables()
end
init_gui()
init_pyshow()
init_tables()
@require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall)
end
end
10 changes: 4 additions & 6 deletions src/Convert/Convert.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,10 @@ include("numpy.jl")
include("pandas.jl")

function __init__()
C.with_gil() do
init_pyconvert()
init_ctypes()
init_numpy()
init_pandas()
end
init_pyconvert()
init_ctypes()
init_numpy()
init_pandas()
end

end
10 changes: 4 additions & 6 deletions src/Core/Core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ include("juliacall.jl")
include("pyconst_macro.jl")

function __init__()
C.with_gil() do
init_consts()
init_datetime()
init_stdlib()
init_juliacall()
end
init_consts()
init_datetime()
init_stdlib()
init_juliacall()
end

end
20 changes: 7 additions & 13 deletions src/GC/GC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,9 @@ Like most PythonCall functions, you must only call this from the main thread.
function enable()
ENABLED[] = true
if !isempty(QUEUE)
C.with_gil(false) do
for ptr in QUEUE
if ptr != C.PyNULL
C.Py_DecRef(ptr)
end
for ptr in QUEUE
if ptr != C.PyNULL
C.Py_DecRef(ptr)
end
end
end
Expand All @@ -55,9 +53,7 @@ end
function enqueue(ptr::C.PyPtr)
if ptr != C.PyNULL && C.CTX.is_initialized
if ENABLED[]
C.with_gil(false) do
C.Py_DecRef(ptr)
end
C.Py_DecRef(ptr)
else
push!(QUEUE, ptr)
end
Expand All @@ -68,11 +64,9 @@ end
function enqueue_all(ptrs)
if C.CTX.is_initialized
if ENABLED[]
C.with_gil(false) do
for ptr in ptrs
if ptr != C.PyNULL
C.Py_DecRef(ptr)
end
for ptr in ptrs
if ptr != C.PyNULL
C.Py_DecRef(ptr)
end
end
else
Expand Down
4 changes: 1 addition & 3 deletions src/JlWrap/C.jl
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,7 @@ function init_c()
end

function __init__()
C.with_gil() do
init_c()
end
init_c()
end

PyJuliaValue_IsNull(o::C.PyPtr) = UnsafePtr{PyJuliaValueObject}(o).value[] == 0
Expand Down
42 changes: 20 additions & 22 deletions src/JlWrap/JlWrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,26 @@ include("set.jl")
include("callback.jl")

function __init__()
Cjl.C.with_gil() do
init_base()
init_raw()
init_any()
init_iter()
init_type()
init_module()
init_io()
init_number()
init_array()
init_vector()
init_dict()
init_set()
init_callback()
# add packages to juliacall
jl = pyjuliacallmodule
jl.Core = Base.Core
jl.Base = Base
jl.Main = Main
jl.Pkg = Pkg
jl.PythonCall = PythonCall
end
init_base()
init_raw()
init_any()
init_iter()
init_type()
init_module()
init_io()
init_number()
init_array()
init_vector()
init_dict()
init_set()
init_callback()
# add packages to juliacall
jl = pyjuliacallmodule
jl.Core = Base.Core
jl.Base = Base
jl.Main = Main
jl.Pkg = Pkg
jl.PythonCall = PythonCall
end

end
Loading