@@ -91,64 +91,71 @@ render_arg(io, arg::Base.RefValue{T}) where {T} = print(io, "Ref{", T, "}")
9191
9292
9393# # version of ccall that calls jl_gc_safe_enter|leave around the inner ccall
94-
95- # TODO : replace with JuliaLang/julia#49933 once merged
96-
9794# note that this is generally only safe with functions that do not call back into Julia.
9895# when callbacks occur, the code should ensure the GC is not running by wrapping the code
9996# in the `@gcunsafe` macro
10097
101- function ccall_macro_lower (func, rettype, types, args, nreq)
102- # instead of re-using ccall or Expr(:foreigncall) to perform argument conversion,
103- # we need to do so ourselves in order to insert a jl_gc_safe_enter|leave
104- # just around the inner ccall
105-
106- cconvert_exprs = []
107- cconvert_args = []
108- for (typ, arg) in zip (types, args)
109- var = gensym (" $(func) _cconvert" )
110- push! (cconvert_args, var)
111- push! (cconvert_exprs, :($ var = Base. cconvert ($ (esc (typ)), $ (esc (arg)))))
112- end
113-
114- unsafe_convert_exprs = []
115- unsafe_convert_args = []
116- for (typ, arg) in zip (types, cconvert_args)
117- var = gensym (" $(func) _unsafe_convert" )
118- push! (unsafe_convert_args, var)
119- push! (unsafe_convert_exprs, :($ var = Base. unsafe_convert ($ (esc (typ)), $ arg)))
120- end
121-
122- call = quote
123- $ (unsafe_convert_exprs... )
124-
125- gc_state = @ccall (jl_gc_safe_enter ():: Int8 )
126- ret = ccall (
127- $ (esc (func)), $ (esc (rettype)), $ (Expr (:tuple , map (esc, types)... )),
128- $ (unsafe_convert_args... )
129- )
130- @ccall (jl_gc_safe_leave (gc_state:: Int8 ):: Cvoid )
131- ret
132- end
133-
134- return quote
135- @inline
136- $ (cconvert_exprs... )
137- GC. @preserve $ (cconvert_args... ) $ (call)
138- end
139- end
98+ const HAS_CCALL_GCSAFE = VERSION >= v " 1.13.0-DEV.70" || v " 1.12-DEV.2029" <= VERSION < v " 1.13-"
14099
141100"""
142- @gcsafe_ccall ...
101+ @gcsafe_ccall ...
143102
144103Call a foreign function just like `@ccall`, but marking it safe for the GC to run. This is
145104useful for functions that may block, so that the GC isn't blocked from running, but may also
146105be required to prevent deadlocks (see JuliaGPU/CUDA.jl#2261).
147106
148107Note that this is generally only safe with non-Julia C functions that do not call back into
149- Julia. When using callbacks, the code should make sure to transition back into GC-unsafe
150- mode using the `@gcunsafe` macro.
108+ the Julia directly.
151109"""
152- macro gcsafe_ccall (expr)
153- return ccall_macro_lower (Base. ccall_macro_parse (expr)... )
154- end
110+ macro gcsafe_ccall end
111+
112+ if HAS_CCALL_GCSAFE
113+ macro gcsafe_ccall (expr)
114+ exprs = Any[:(gc_safe = true ), expr]
115+ return Base. ccall_macro_lower ((:ccall ), Base. ccall_macro_parse (exprs)... )
116+ end
117+ else
118+ function ccall_macro_lower (func, rettype, types, args, nreq)
119+ # instead of re-using ccall or Expr(:foreigncall) to perform argument conversion,
120+ # we need to do so ourselves in order to insert a jl_gc_safe_enter|leave
121+ # just around the inner ccall
122+
123+ cconvert_exprs = []
124+ cconvert_args = []
125+ for (typ, arg) in zip (types, args)
126+ var = gensym (" $(func) _cconvert" )
127+ push! (cconvert_args, var)
128+ push! (cconvert_exprs, :($ var = Base. cconvert ($ (esc (typ)), $ (esc (arg)))))
129+ end
130+
131+ unsafe_convert_exprs = []
132+ unsafe_convert_args = []
133+ for (typ, arg) in zip (types, cconvert_args)
134+ var = gensym (" $(func) _unsafe_convert" )
135+ push! (unsafe_convert_args, var)
136+ push! (unsafe_convert_exprs, :($ var = Base. unsafe_convert ($ (esc (typ)), $ arg)))
137+ end
138+
139+ call = quote
140+ $ (unsafe_convert_exprs... )
141+
142+ gc_state = @ccall (jl_gc_safe_enter ():: Int8 )
143+ ret = ccall (
144+ $ (esc (func)), $ (esc (rettype)), $ (Expr (:tuple , map (esc, types)... )),
145+ $ (unsafe_convert_args... )
146+ )
147+ @ccall (jl_gc_safe_leave (gc_state:: Int8 ):: Cvoid )
148+ ret
149+ end
150+
151+ return quote
152+ @inline
153+ $ (cconvert_exprs... )
154+ GC. @preserve $ (cconvert_args... ) $ (call)
155+ end
156+ end
157+
158+ macro gcsafe_ccall (expr)
159+ return ccall_macro_lower (Base. ccall_macro_parse (expr)... )
160+ end
161+ end # HAS_CCALL_GCSAFE
0 commit comments